How to rule the Pivot

Interface can be used as parameters to configure code. And since XAF is based on interfaces, it features technologies like the Application Model and Domain Components, which in turn offer what no other frameworks do - multiple inheritance, flexible design, no match in reusability, etc. The Application Model, for example, describes all parts of a business application and can be further extended using interfaces. So, our code should simply query the values of these Application Model interfaces and operate accordingly. Let’s name these interfaces Rules. The next step is to check out existing implementations and discuss a Pivot control ruling concept. Make a note here that instead of the Pivot, it be any control, our goal is to describe behaviors in XAF’s Application Model using such Rules/interfaces, then implement these behaviors in a Controller and simply copy paste this controller to any project!

All the code needed for today’s discussion can be found in the XVideoRental demo in the Common.Win project under the NameSpaces: Common.Win.ModelAdapter, Common.Win.ColumnView.RepositoryItems, Common.Win.PivotGridControl.

Take a look at this ruling concept/idea in action in the XAF Validation module. In the image bellow we see a set of interfaces that describe validation rules. The Validation Engine simply queries them and validates the objects accordingly.

image

Similar ruling based stuff can be found in our community project eXpandFrameWork, under a whole Logic Architecture concept. A few modules that use this architecture are AdditionalViewControls, ModelArtifact, MasterDetail, ConditionalDetailViews  The logic architecture is based in the composition over inheritance principle, meaning that it can make our rules amazingly powerful!. This is because we do not extend the IModelListView, but rather add the IModelListViews and other model artifacts to root model nodes like the ConditionalControllerState and LogicConditionalActionState we see in the image bellow.

 image

In this post, however, we will concentrate on our XVideoRental demo. Take a look at this traditional Windows form taken from the legacy VideoRent application of our Windows Components Suite.

image

A traditional developer created a multidimensional UI given a collection of ChartPrice objects. For example, one dimension is the type of the price (DVD,Blue-Ray,Video CD), another one is the day number 1-7 and so on. As you can see, the developer to implement this user interface used 3 tabs and 9x3 controls. Three of them must accept integers only and all other double numbers. This is an acceptable design, it is however, not flexible. Here are a few reasons:

  1. The number of days is fixed to add more days (e.g. up to 10), more controls are needed.
  2. User interaction is needed from the end user if he/she wants to see prices for Blue-Ray, he must click on the assigned tab.
  3. The code that implements this works only for specific Windows form.

THE XAF WAY

To create the above multidimensional UI, we can use the PivotGridListEditor and create rules/interfaces that we can use to describe what the traditional form does. Since we will work with Rules/interfaces which will extend the Application Model, this methodology is not bound to other model artifacts like Business Objects or Views.

However, at this point, let’s assign a PivotGridListEditor to the collection of ChartPrice objects to see the starting point and to have a point of reference.

image

The PivotGridListEditor is perfect for multidimensional analysis, making our UI more flexible than the legacy one. However, PivotGridListEditor is missing some things (not editable,row header formatting, cells formatting, object saving). Next, we will discuss how to build all that stuff with XAF and make them reusable by all of our projects!

Extending the Application Model to host different rule types

We must first create a collection of abstract rules and extend our Application Model’s IModelListView. To extend the Application Model, follow this help document making use of the interfaces listed below.

public interface IModelPivotRules : IModelNode, IModelList<IModelPivotRule> {

}

 

[ModelAbstractClass]

public interface IModelPivotRule : IModelNodeEnabled {

 

}

So after extending the model the Model Editor for IModelListView will look like the following image.

imagetEd

You may wonder why we chose to extend in a deeper level than IModelListView. This was done, because we wanted to group the new Rules with the PivotGridListEditor option interfaces which are discussed in Dressing up our classes – Date with a model tonight.

Control the range of the cells

The next step is to design an interface that can help us to apply rules to certain Pivot control cells. Thus, we require an interface with two properties - Start, End

[ModelAbstractClass]

public interface IModelPivotSelectionRule : IModelPivotRule {

    Point Start { get; set; }

    Point End { get; set; }

}

No other action is required here. XAF’s TypesInfo system is already aware of the IModelPivotSelectionRule since it derives from the already registered IModelPivotRule.

Formating the Pivot Cells

To format Pivot cells we need an Interface that:

a) defines the range of the cells (eg. IModelPivotSelectionRule) .
b) defines the PivotArea where the cells are located (Row, Column, Data).
c) allows format configuration.

The IModelFormatRule interface below fulfills of all the above-stated requirements.

public interface IModelPivotArea : IModelNode {

    PivotArea PivotArea { get; set; }

}

public interface IModelFormatRule : IModelPivotArea, IModelFormatInfo, IModelPivotSelectionRule {

    [RuleValueComparison("IModelFormatRule_PivotArea_not_filter", DefaultContexts.Save, ValueComparisonType.NotEquals, PivotArea.FilterArea)]

    [DefaultValue(PivotArea.ColumnArea)]

    new PivotArea PivotArea { get; set; }

}

[ModelAbstractClass]

public interface IModelFormatInfo : IModelNode {

    string FormatString { get; set; }

    FormatType FormatType { get; set; }

}

Again no other action is required here. XAF’s TypesInfo system is already aware of the IModelPivotSelectionRule since it derives from the already registered IModelPivotRule. In addition, the IModelFormatRule is not marked with  the ModelAbstractAttribute therefore the Model Editor will automatically add a menu entry as shown,

 image

Now, we are ready to create a FormatRule for all row headers to display the info that the Legacy Windows form displays.

image

In the image we see that we created a FormatRule for RowArea cells that Start at X=0, Y=1 and End at the last cell X=-1, Y=-1. This rule will instruct a Controller to modify the initial ListView as shown below.

image

Next we will add one more FormatRule for the first row header.

image

What is different with this FormatRule  is the End X=0, Y=0 which points to the first row header and of course the FormatString. So, XAF will first evaluate the “All row headers format” rule and then the “First Row Header” resulting in the following UI.

imageina

Finally, we create a similar FormatRule for the second row header.

image

…which will result in the following UI.

image

Using a declarative runtime approach we managed to format all row headers-amazing!

Make all Pivot cells editable and with double Datatype

We are now ready to start modeling the legacy windows form behavior. So, we need to make the Pivot cells editable therefore we first query our Support Center to see how this can be done –> E1232. From this example we understand that we can subscribe to certain events and replace the RepositoryItem of a Pivot cell. We already have a range of Pivot cells defined from the IModelPivotSelectionRule above, and are interested only in double and integer based Repositoryitems - therefore an interface like the one below is sufficient.

[ModelDisplayName("SpinEdit")]

public interface IModelPivotSpinEditRule : IModelPivotSelectionRule {

    IModelRepositoryItemSpinEdit SpinEdit { get; }

}

 

This interface derives from the IModelPivotSelectionRule so it will provide a range of Pivot cells whose RepositoryItems will be replaced with a RepositoryItemSpinEdit (int, double). The IModelRepositoryItemSpinEdit is an interface that describes all properties of a RepositoryItemSpinEdit and can be created either by hand or automatically as discussed in Dressing up our classes – Date with a model tonight!

 

The next step is to create the first rule that will make all Pivot cells of the data area editable. Of course we need to write code to query this rule and also save this object (like in E1232). However for the sake of simplicity and as I already stated in the beginning of this post, all code can be found in the Common.Win project of our XVideoRental demo. Look for the Common.Win.PivotGridControl.PivotGridController.

 

imageinstrcuts

 

In the image above: End X=-1, Y=-1 instructs our code to include all cells of the data area. Moreover since this is a RepositoryItem replacement rule, it assumes that row and column headers are excluded, so X=0, Y=0 point to the top left data cell.

 

With this rule, the UI will be editable and will accept double numbers as shown below.

 

image

 

The last rule will help us format the edit value of the first row (Default # of Rental Days) to accept integers only as shown below by simply setting the IsFloatValue to false.

 

 

image

 

More Rule Types

In XVideoRental we have more Rule types than the ones discussed in this post . It is rather easy to implement more and we would appreciate your ideas and contributions. So please feel free to use our Support Center to share them with the rest of our community. A list of the already implemented Pivot Rules is shown bellow. 

image

Controlling end user selection

One of our objectives as developers is to provide our customers with tools that make their lives easier. For example, the PivotGridListEditor contains two components (PivotGridControl and a ChartControl hosted inside a LayoutControl). The ChartControl has as datasource the PivotGridControl. As a result when the end user selects a range of cells in the Pivot the ChartControl automatically renders that selection as shown.

image

When we close the view or the application, however, the selection is lost and the end user has to do again.  I really do not like to spend my time doing repetitive tasks. It is much easier an faster to model it in the Application Model once at for all! To implement this remember selected cells functionality we need an interface to extend the Application Model.

public interface IModelPivotGridSelection : IModelNode {

    Rectangle Rectangle { get; set; }

    [DefaultValue(true)]

    bool Synchronize { get; set; }

}

 

When the Synchronise property is set to true, our code will persist the end user cell selection in the Rectangle property, when Synchronize is set to false, we can only use this functionality for preconfiguring a cell selection when the view opens.

 

image

 

 

The XVideoRental demo contains a large number of Application Model Rules, and I will probably need a large number of posts to talk about all of them. So I will concentrating in the more important ones. Feel free to explore the demo and contact us with your questions and ideas!

 

As always happy XAFing!

no comments
No Comments

Please login or register to post comments.