Wednesday, January 16, 2013

How to rule the Pivot

To configure our code we can simply use interfaces as parameters. XAF design is based on interfacesrefore it features amazing technologies like the Application Model and Domain Components which make available what no other framework offers (eg 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 and let’s try first to get a taste of existing implementations and then discuss a Pivot control ruling concept. Note here that instead of a Pivot it be any control, our goal is to describe behaviors in XAF’s Application Model, then implement them in a Controller and simply copy paste this controller to any project!

All the code needed for today’s discussion can be found in XVideoRental demo in 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 XAF’s 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 rather we add IModelListViews and other model artifacts to root model nodes like the ConditionalControllerState, LogicConditionalActionState we see in the image bellow.

 image

In this post however we will not dive so deep as our community project and we will concentrate to our XVideoRental demo. Take a look at this traditional windows form taken from the legacy VideoRent application of our Windows components suite.

image

The traditional developer needs to create a multidimensional UI given a collection of ChartPrice objects. One dimension is the type of the price (DVD,Blue-Ray,Video CD). Next one is the day number 1-7, third one is the different type in price double or integer for Default # of Rental Days. As you can see the traditional developer to implement this user interface used 3 tabs, 9x3 controls. Three of them must accept integers only and all other double numbers. This is an acceptable design however not flexible and here are a few reasons:

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

THE XAF WAY

XAF is a really smart framework, using it is inevitable that we will become equally smart cause we have unparalleled tools to work with. So, to create  a multidimensional UI we can simply use the PivotGridListEditor and create rules that we can use to describe what the traditional form does. Since we are talking about rules that will extend our Application Model we already start building an abstract mechanism that can be applied to any view and any object even at runtime with the help of Model Editor. However at this point let’s assign a PivotGridListEditor to the collection of ChartPrice objects to see the starting point and to have a comparing reference.

image

The PivotGridListEditor is perfect for multidimensional analysis thus our UI is already more flexible than the legacy one. However it is missing a lot of stuff (not editable,row header fromatting, cells formatting, object saving). We will discuss how to build all that stuff the XAF way and make them reusable to all of our projects!

Extending the Application Model to host different rule types

First lets create a collection of abstract rules and extend our Application Model’s IModelListView. To extend the Application Model we can follow this help document with make use of the bellow interfaces.

public interface IModelPivotRules : IModelNode, IModelList<IModelPivotRule> {

}

 

[ModelAbstractClass]

public interface IModelPivotRule : IModelNodeEnabled {

 

}

We choose to extend in a deeper level than IModelListView because we want to group the new Rules with the PivotGridListEditor option interfaces which are discussed in Dressing up our classes – Date with a model tonight!. So after extending the model the Model Editor for IModelListView will look like the following image.

imagetEd

Control the range of the cells

Next step is to design an interface that can help us to apply rules to certain Pivot control cells, so we need 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 IModelPivotSelectionRule since it derives from the already registered IModelPivotRule.

Formating the Pivot Cells

To format the cells of Pivot 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 interface bellow IModelFormatRule interface fulfills all the above 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 IModelPivotSelectionRule since it derives from the already registered IModelPivotRule. In addition 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 bellow.

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 first will evaluate first 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

that will result in the following UI,

image

Using a declarative runtime approach we managed to format all row headers, XAF really teaches us amazing stuff!

Next let’s make PivotGridListEditor editable and we finished cloning the legacy functionality following an unbelievable flexible way – the XAF way!

All Pivot cells editable and double

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 we are interested only in double and integer based Repositoryitems therefore an interface like bellow is sufficient.

[ModelDisplayName("SpinEdit")]

public interface IModelPivotSpinEditRule : IModelPivotSelectionRule {

    IModelRepositoryItemSpinEdit SpinEdit { get; }

}

 

The above interface derives from IModelPivotSelectionRule so it will provide a range of Pivot cells which their 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!

 

Let’s now 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 as in E1232. However for the sake of simplicity as I already said in the beginning of this post all the code can be found in the Common.Win project of our XVideoRental demo. In this case 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 accept double numbers as shown bellow,

 

image

 

Last rule will help us to format the edit value of the first row (Default # of Rental Days) to accept integers only as shown bellow, 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

FieldToolTip rule

Tooltips are amazingly powerful and we already discussed them in depth at Tooltips to the max - expressive UI. However there I only posted a screenshot about pivot tooltips but I haven’t explained more since I needed more info that could make that post too hard to follow. Now we do have that extra info and I am talking about the IModelPivotSelectionRule interface which allows us to associate interfaces/rules/classes etc with a range of Pivot cells.

image

You can learn how to associate a class in this case the MovieToolTipController with an Application Model node at Tooltips to the max - expressive UI. under the TooltipController paragraph.

Try to imagine how expressive can a Pivot control become with different tooltips for different cells!

image

We will discuss the rest of the PivotRules (DrawCellRule, GroupIntervalRule, FieldSort) in a future post.

For now I want again to ask you all for your contributions/ideas regarding everything you see in our posts. Let’s use your real world experience and your XAF skills to improve our framework even more.

Controlling end user selection

As developers we should provide tools to our customers that can make their life easier. Let’s see what this means, PivotGridListEditor contains two components which are a PivotGridControl and a ChartControl hosted inside a LayoutControl. The ChartControl has as datasource the PivotGridControl so when the end user selects a range of cells the ChartControl automatically renders this selection as shown.

image

However when we close the view or the application the selection is lost and the end user has do it again. Moreover if we need to preconfigure a selection when the view opens we need to follow a repetitive way, that is search our Support Center for a similar sample eg select pivotgrid cells and then replicate something similar for all projects, views. 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 we need an interface to extend the Application Model.

public interface IModelPivotGridSelection : IModelNode {

    Rectangle Rectangle { get; set; }

    [DefaultValue(true)]

    bool Synchronize { get; set; }

}

 

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

 

image

 

Moreover there are cases where we want to control the cell selection eg when a user selects a cell to auto select all cells in the row sparing his time, or disallow multiple column selection. I am sure it is pretty clear that all we need are a few more properties in the IModelPivotGridSelection interface to create amazing and reusable functionalities.

 

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

 

As always happy XAFing with the smartest framework of all!

Subscribe to XAF feed
Subscribe to community feed

DiggIt!

0 comments:

Post a Comment