-
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.

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.

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.

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:
-
The number of days is fixed, to add more days (eg. up to 10) more controls are needed.
-
User interaction is needed from the end user, if he wants to see prices for Blue-Ray he must click on the assigned tab.
-
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.

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.
tEd
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,

Now we are ready to create a FormatRule for all row headers to display the info that the legacy windows form displays.

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.

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

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.
ina
Finally we create a similar FormatRule for the second row header,

that will result in the following UI,

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.
instrcuts
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,

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.

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.

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.

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!

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.

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.

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!
-
UI simply depends on the smartness of our components. However the visible UI space is limited and most of the information is hidden behind components (tabs, popup forms etc). Therefore to display this hidden info user interaction is required. Tooltips however do not require any user interaction and our Suite supports tooltips with html formatting even in windows platform. We can already empower the detailed views of our XAF applications with native tooltip support as described in this help document. However when developing in XAF the sky’s the limit and in this post we will discuss ways to create tooltips as demoed in our XVideoRental RWA.
DataOnToolTip
By this we mean that we want to push any data a property of a business object has to a tooltip. Therefore, first we need to create a interface and extend our Application Model columns as described in our documentation,
[ModelAbstractClass]
public interface IModelColumnTooltipData : IModelColumn {
IModelTooltipData TooltipData { get; }
}
public interface IModelTooltipData : IModelNode {
[Category("DataOnToolTip")]
bool DataOnToolTip { get; set; }
[Category("DataOnToolTip")]
int MaxHeight { get; set; }
[Category("DataOnToolTip")]
int MaxWidth { get; set; }
}
public class GridViewImageTextToolTipController : ViewController<ListView>, IModelExtender {
public void ExtendModelInterfaces(ModelInterfaceExtenders extenders) {
extenders.Add<IModelColumn, IModelColumnTooltipData>();
}
The above will extend the Application Model as shown,

Next, we need to implement a method that when DataOnTooltip attribute is set will display the data in a tooltip like,

Of course due to the MVC XAF architecture it is really easy to reuse this functionality in any XAF project without not even one line of code!
ToolTipText
Now, how about a different case? Lets say that we have a complex Advanced Banded ListView and we want to guide end user to double click to a row area to see more info about the record. For this again we need to extend the Application Model with an attribute like,
public interface IModelTooltipData : IModelNode {
[Editor(typeof(MultilineStringEditor), typeof(UITypeEditor))]
string ToolTipText { get; set; }
// ...
Then we can use the Model Editor to assign the text we want in the ToolTipText attribute and XAF will do the rest for us in any project!

ToolTipController
Extending the Application Model in order to be able to associate a class (controller) with any of its nodes can be done easily. First we add one more property to our IModelToolTipData interface like,
public interface IModelTooltipData : IModelNode {
[DataSourceProperty("ToolTipControllers")]
[TypeConverter(typeof(StringToTypeConverterBase))]
Type ToolTipController { get; set; }
[Browsable(false)]
IEnumerable<Type> ToolTipControllers { get; }
The TypeConverter attribute will convert the type to a string so it will be possible for the Model Editor to show it and the DataSourceProperty attribute will populate the Types (Controllers) we want. What's left is to decide which classes will be in that list. This can be done be writing a Domain Logic for the non browsable ToolTipControllers enumeration like the following,
[DomainLogic(typeof(IModelTooltipData))]
public class IModelToolTipControllerDomainLogic {
public static IEnumerable<Type> Get_ToolTipControllers(IModelToolTipController modelToolTipController) {
return FindTypeDescenants(typeof(ObjectToolTipController));
}
protected static IEnumerable<Type> FindTypeDescenants(Type type) {
var typeInfo = XafTypesInfo.Instance.FindTypeInfo(type);
return ReflectionHelper.FindTypeDescendants(typeInfo).Where(info => !info.IsAbstract).Select(info => info.Type);
}
}
We have finished Application Model extension so let’s see how simple yet amazingly powerful is to write and apply such a controller for our Movie business object. So for a very simple ToolTipController like,
public class MovieToolTipController : ObjectToolTipController {
const int MaxPhotoWidth = 120, MaxPhotoHeight = 120;
public MovieToolTipController(Control parent) : base(parent) { }
protected override void InitToolTipItem(ToolTipItem item) {
var movie = ObjectSpace.FindObject<Movie>(CriteriaOperator.Parse("MovieTitle=?", EditObject));
var photo = movie.Photo;
if (photo != null)
item.Image = photo.CreateImage(MaxPhotoWidth, MaxPhotoHeight);
item.Text = GetMovieInfoHtml(movie);
}
public string GetMovieInfoHtml(Movie movie) {
return string.Format("<b>{0}</b>\r\n<i>{2:D}</i>\r\r\n{1}", movie.Title, movie.Plot, movie.ReleaseDate);
}
}
When assign it to a listview column,

XAF will popup an html formatted tooltip,

or we can use a similar approach for PivotGridListEditors

Everything discussed in this post exist in the Common.Win project under the Common.Win.General.ToolTip namespace of our XVideoRental demo.
Let us know if you have questions or subjects we want us to cover. Happy XAFing to everybody!
-
This post will be on how to use the approach described in Fast prototyping requires an initial data import mechanism with Excel as input source. The technic is based on System.Data.DataSet class and can be applied to any type of input source!
Thanks to your reports and of course Slava’s help (XPO guru), XVideoRental importing mechanism has been improved a lot and now is faster, has notification events and is decoupled from XAF’s TypesInfo system. This makes it possible to simply copy the ImportData.cs file found in Common.Win project and use it in non XAF solutions!
In previous version this importing mechanism worked only when matching in types of input and output members. This means that if my output Oid property was a System.Guid then input should be of the same type. Now we have workaround this minor issue. If conversion is possible it will be done automatically without the need of any configuration or extra coding!
To better design, support, extend and describe the importing mechanism I used Mspec a functional testing framework and I open source the specifications in our community project eXpandFramework. These follow bellow,
MemberMapper, When Class Has a flag that includes all members
» should collect all members that belong to the class
» should not collect any base class member
» should create new members for each one of them
MemberMapper, When class does not have a flag that includes all ownmembers
» should not create members for those not marked with the attribute
» should create members and name them according to the attribute data
» should create a key property if not included in the conficuration
MemberMapper, When class attribute has data for base members
» should create and name them according to the attribute data
» should map their attributes
MemberMapper, When class is marked to include all member but member is marked seperately
» should use the member marking
MemberMapper, When mapping a referenced member
» should create a member with a dynamic type ownwer
MemberMapper, When reference type is not includedIN the configuration
» should create non reference member
ClassMapper, When creating dynamic classes
» should Create Classes only for the ones that have a marking attribute
» should name the classes taking data from marking attribute
ClassMapper, When class has many to many collection marked for importing
» should create intermediate classes
» should create an auto genareted key for this class
» should create 2 columns with names taken from the marked attribute
DictionaryMapper, When is mapping a dictionary
» should map all marked objects
InitDataImporter, When importing an object
» should create a new output object
» should assign all mapped properties
InitDataImporter, When input membertype is different than output
» should convert the value when simple type
» should convert the value when reference type
21 passed, 0 failed, 0 skipped, took 1.61 seconds (Machine.Specifications 0.5.2-98b543c).
The above specifications are evaluated with every eXpand build and you can see them in eXpand’s build server. Take a quick look at their code located in github to see how easy it is to write them (http://goo.gl/TNv4d).
Now lets see how to use our magic XPO ORM to import into the real world business domain like the one of our XVideoRental demo,

For the sake of complexity the input source will be a list of excel files and not just a simple Excel file with many sheets.

XPO supports a DataStore provider which is based on DataSet. So, first we fill a DataSet with the excel files and for this I will use some DataSet extension methods I contributed to eXpand (see http://goo.gl/TF26g)
static DataSet DataSet() {
var dataSet = new DataSet();
dataSet.ImportExcelXLS(new[]{
"Customer", "Receipt", "Company", "CompanyType", "Country", "Employee", "Language", "Movie", "MovieArtist",
"MovieArtistLine", "MovieCategory", "MovieCategoryPrice", "MovieCompany", "MovieItem",
"MovieMovies_CountryCountries", "MoviePicture","Person","Artist","ArtistPicture","Rent"
});
return dataSet;
}
Now we are ready to create a UnitOfWork with this DataSet as DataStore like,
var inputUnitOfWork = new UnitOfWork(new SimpleDataLayer(new DataSetDataStore(DataSet(), AutoCreateOption.None)));
and finally call the Import method of the InitDataImporter class as shown bellow
var initDataImporter = new InitDataImporter();
var unitOfWork = OutputUnitOfWork();
var inputUnitOfWork = new UnitOfWork(new SimpleDataLayer(new DataSetDataStore(DataSet(), AutoCreateOption.None)));
initDataImporter.Import(() => new UnitOfWork(unitOfWork.ObjectLayer), () => new UnitOfWork(inputUnitOfWork.ObjectLayer));
This simple, however powerful technic can be applied to any type of input source as long as you are able to fill a DataSet!
You can download a sample project was created with v12.2.5 of our Suite from Importer.Console.
Happy New Year to everybody!
-
XAF knowledge base is really rich and in our Support Center you can find solutions for all common business problems. Moreover our community project www.expandframework.com has tones of reusable solutions, we collected a few of them and applied them to the video rent business. The demo is available with 12.2.4 version of our Suite and can be found in the same folder with the other amazing XAF demos!
XAF is a framework that provides the tools that a developer needs for building business solutions.
- A state of the art multi layered configuration system – The Application Model.
- A robust and flexible Security System that can be used to protect our data and control the auto generation of the UI based on Role permissions
- Its own reflection system (TypesInfo)– with amazingly simple ways to do what .NET does not offer eg. Runtime members, dynamic attributes etc.
- A well designed architecture to guide you where you should put your code. Moreover a very flexible modularization for structuring and further supporting any solution.
- WinForms/ASP.NET integration for a large number of our components
- Rich documentation and a click and run SDK!
XVideoRental is a real world application (RWA). It is designed as a clone of our WinForms VideoRent application and demos only a small part of XAF capabilities. XAF provides the tools/architecture to do extraordinary things so we have followed a (no code)/(design at runtime) approach!. We recommend you to open the legacy Winforms demo and XVideoRental side by side and compare how much faster and richer is XAF development versus the traditional one. Moreover take a look at this help document that extensively compares traditional vs XAF development.
- XVideoRental uses a mechanism to serialize classes into Application Model and control them further from there! Therefore minimizes the learning curve since it is based on your existing component knowledge. (see this blog)
- It is a modeling rather than development technic. In addition allows further modeling at runtime since XAF already provides a runtime model editor.
- Implementations are collected from our usual places (Support Center / Code Central) / www.expandframework.com.
The XVideoRental demo has three projects:
Common.Win
This is a library (not XAF module) and contains 95% of the code needed to model the VideoRental business! As a library can be reused from all domains and not only for video rental business. By extending the model as discussed in Dressing up our classes – Date with a model tonight! it is possible to create an abstract mechanism and control any class/component from there. Since all business operations can be modeled, the library contains controllers like NetIncomeController, TopObjectController that map to the real world meanings and can be applied to any domain. The XAF Application Model serves as an abstraction from technology and business specifics. This module is assembled by collecting the classes/implementations from our Support Center and from our community project www.expandframework.com.
XVideoRental.Module.Win
References Common.Win library and simple initializes the required classes/controllers by deriving from the abstract implementation of Common.Win library. However even if it is possible to “model” any behavior sometimes technical depth must be considered. Therefore in the project you will find a small number of video rental specific classes. In this project you can also find the model differences for this business domain.
XVideoRental.Win
This is the application project and contains no code. Only a few default configurations like module and security registrations.
In the next post we are going to discuss the steps involved in building this application. I remind you again that all code functionality is borrowed from our community, this means that code / ideas really belong to you! We welcome more of your contributions and ideas to build even more wonderful applications. Please explore this demo and we are waiting for your feedback in order to blog more about features that interest you.
A similar version can found in our community project www.expandframework.com. This version has exactly the same functionality as the original demo. However it references directly the eXpand framework so the Common.Win project does not exist nor the initialization of the controllers in the XVideoRental.Module.Win.
We are looking forward for your feedback and contributions in order to make this demo even more powerful! In its current state, a developer can replace before lunch all the business objects with objects of a different business domain then package the application and go to customer and continue development there, at runtime! The final goal as developers is to build such configurable applications that business users can use and modify and shift this weight of our backs. XAF provides all the tools for this and this demo is a proof for this!
Bellow is a short video that shows this demo. You can find about two more dozen of images of this demo in our FB group
PS: A thanks to everybody that already provided feedback and reported issues with this demo. We already provided a newer version with improved performance and you can find it here. For posts related to the XVideoRental demo please subscribe to to the XVideoRental tag
Happy XAFing!
-
Classes are in a sense behavior libraries. To initialize or configure them, we can use their properties. Serialization is a technic that helps distribute the state of our classes. In this post we will discuss how to serialize any class in the multi-layer XAF model! Then we finish with the model synchronizers which will control the class. Having a class or a part of a class serialized in the model makes it possible to continue development there without writing more code (declarative/runtime approach).
Runtime classes
In .NET is super easy to create runtime classes or interfaces. The following snippet will create a assembly with a Dynamic class.
var provider = CodeDomProvider.CreateProvider("c#");
var results = provider.CompileAssemblyFromSource(new CompilerParameters(), new[] { @"public class DynamicClass{}" });
Assembly compiledAssembly = results.CompiledAssembly;
Modeling
XAF’s super advanced and simple model technology is using interfaces for design and further extension. This is well documented How to: Extend Application Model. To serialize any class on the XAF model we simply need to use reflection, extract an interface from the class and extend any part of the model we want with it.
Let’s see a few examples using XAF build-in components.
1) GridListEditor
XAF’s GridListEditor is based on the GridView class which is a very sophisticated component with a lot of properties. Serializing it into the model allow us to control it from there. Using the model it is possible to work at runtime and since we have a lot of properties it is wise to serialize their help as well (see red arrow).

2) ChartListEditor
This is a very useful editor that also needs better control from our model. Note that this model serialization is reusable from all our projects!

This technic can boost our runtime experience and make it possible to work side by side with our customer building really fast. Furthermore it is applicable to any class or component. Let’s a few more interesting examples.
3) Repository Items
XAF’s DX PropertyEditors render DX controls which store their configuration in RepositoryItem classes. We can serialize all ReporitoryItem descendants and extend the IModelColumn. As a result by simply changing a model attribute we can do things at runtime that with a code approach would be very time consuming.

4) The SchedulerListEditor

5) The PivotListEditor
This one uses the same serialization approach however since this is a very useful editor we modeled a few extra behaviors – the pivot rules!. We would probably create a separate post about them.

Furthermore here we need to notice that we can model business meanings such as NetIncome, so for the following model modifications,

XAF will render the View bellow without any coding or dependency to any object!
Another example, when we talk about the TopObject meaning, we can model it like

and XAF will give us the following View again without writing not even one line of code (no code==no bugs)

Model synchronization
ModelSynchronizers can be used to:
a) set up an entity according to the configuration stored in the Application Model
b) Persists the configuration of an entity into the Application Model
Model’s nature makes it very abstract so since the attributes of the model are automatically generated from the properties of a class, its rather easy to do the opposite. Therefore we can write an abstract class that will implement IModelSynchronizable interface. The method SynchronizeValues is reading from any class and updates the model. The method ApplyValues is reading the values of the model and synchronize any class that properties match model’s attribute Ids.
protected void SynchronizeValues(ModelNode modelNode, object component, PropertyDescriptorCollection properties) {
foreach (var valueInfo in GetModelValueInfos(modelNode)) {
var propertyDescriptor = properties.Find(valueInfo.Name, false);
if (propertyDescriptor != null) {
var propertyValue = GetPropertyValue(component, propertyDescriptor, valueInfo, modelNode);
var modelValue = GetSynchronizeValuesNodeValue(modelNode, valueInfo, propertyDescriptor, valueInfo.PropertyType.IsNullableType(), component);
if (modelValue != null && !modelValue.Equals(propertyValue)) {
modelNode.SetValue(valueInfo.Name, propertyValue);
}
}
}
}
protected void ApplyValues(ModelNode node, object component, PropertyDescriptorCollection properties) { foreach (var valueInfo in GetModelValueInfos(node)) {
var propertyDescriptor = properties.Find(valueInfo.Name, false);
if (propertyDescriptor != null) {
var nodeValue = GetApplyModelNodeValue(node, valueInfo);
if (nodeValue != null) {
var propertyType = propertyDescriptor.PropertyType;
var propertyValue = propertyDescriptor.GetValue(component);
if ((!IsDefaultCoreValue(nodeValue, propertyType) || (!nodeValue.Equals(propertyValue))) && propertyType.IsValidEnum(nodeValue)) {
if (!nodeValue.Equals(propertyValue))
propertyDescriptor.SetValue(component, nodeValue);
}
}
}
}
}
Finally for each component we want to synchronize we create a descendant of the above implementation. For example,
AdvBandedListEditor
public class AdvBandedViewOptionsSynchronizer : ComponentSynchronizer<DevExpress.XtraGrid.Views.BandedGrid.AdvBandedGridView, IModelOptionsAdvBandedView> {
public AdvBandedViewOptionsSynchronizer(AdvBandedListEditor control)
: base(control.GridView, control.Model.OptionsAdvBandedView, ((IColumnViewEditor)control).OverrideViewDesignMode) {
}
}
ChartControlListEditor
public class ChartControlSynchronizer : ComponentSynchronizer<DevExpress.XtraCharts.ChartControl, IModelOptionsChart> {
readonly XafApplication _application;
We have discussed ways to model components into a distributable layer that describes a XAF. Even more we show how simple would be a model representation of business meanings (eg. NetIncome). It is clear that these tools are reusable from any project. We only need to feed XAF with a business domain and a few model modifications even in runtime to be able to have a working solution! A solution so rich in features that it is impossible to implement using the traditional approach.
The code and screen shots are taken from the XVideoRental application. This demo that can be found along with the other XAF demos in v12.2. Next posts will be about this new demo that really proves how XAF can save our time by lifting the development to the runtime!
P.S. If you are a facebook fun you can support us with a like for our new XAF page.
We are happy to read your feedback about this!. Remember that your questions are the best candidates for future posts.
Happy XAFing!


-
XAF has a great security system which can be used to protect our data either at client or server side. There is also great support for modifying the Security behavior at runtime using a permission matrix. However we need to provide initial before distributing our application. In this post we are going to discuss a way connecting methods that describe permission policies with our domain objects using metadata (Attributes).
For supplying initial data XAF provides a well documented approach through ModuleUpdaters. We can use them and write methods that create initial permissions. There are also many extension methods that can help us write faster code,

Full permission policy
This policy can be applied to any role and give full permission for the related objects. To connect a domain object with a method we need to do the following:
- Define a FullPermissionAttribute as,
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class FullPermissionAttribute : Attribute {
}
- Decorate all related objects
[FullPermission]
public class MovieArtist : VideoRentalBaseObject {
[FullPermission]
public class Artist : VideoPerson {
- With the use of XAF’s sub types info metadata API write an abstract algorithm that will enumerate all domain objects and assign full permission to them for a certain role
public static void CreateFullPermissionAttributes(this SecuritySystemRole systemRole, bool defaultAllowValues = true) {
var persistentTypes = XafTypesInfo.Instance.PersistentTypes.Where(info => info.FindAttribute<FullPermissionAttribute>() != null);
foreach (var typeInfo in persistentTypes) {
systemRole.CreateTypePermission(typeInfo.Type, defaultAllowValues);
}
}
public static SecuritySystemTypePermissionObject CreateTypePermission(this SecuritySystemRole systemRole, Type targetType, bool defaultAllowValues = true) {
var permission = systemRole.CreateTypePermission(targetType);
permission.TargetType = targetType;
permission.AllowDelete = defaultAllowValues;
permission.AllowNavigate = defaultAllowValues;
permission.AllowRead = defaultAllowValues;
permission.AllowWrite = defaultAllowValues;
permission.AllowCreate = defaultAllowValues;
return permission;
}
- Invoke the CreateFullPermissionAttributes form the roles you want to apply inside the ModuleUpdater’s
public override void UpdateDatabaseAfterUpdateSchema() {
base.UpdateDatabaseAfterUpdateSchema();
var employersRole = ObjectSpace.GetRole<SecuritySystemRole>("Employers");
employersRole.CreateFullPermissionAttributes();
Permission Behavior policy
A common policy for an application is a “settings” policy. Which really means that for certain roles like the employee role there should be limited access to objects that store “settings” data. To implement this we can follow the follow steps
- Define an attribute to decorate our objects as in previous step. This time we do not know the policy name (settings) so we design this as an Enum parameter in the ctor.
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class PermissionBehaviorAttribute : Attribute {
readonly string _name;
public PermissionBehaviorAttribute(object @enum) {
if (!@enum.GetType().IsEnum)
throw new NotImplementedException();
_name = Enum.GetName(@enum.GetType(), @enum);
}
public PermissionBehaviorAttribute(string name) {
_name = name;
}
public string Name {
get { return _name; }
}
}
- Design an enumeration to hold all possible security policies
public enum PermissionBehavior {
Admin,
Settings,
ReadOnlyAccess
}
- Decorate related objects
[PermissionBehavior(PermissionBehavior.ReadOnlyAccess)]
public class Language : VideoRentalBaseObject {
- Create a method to describe the ReadOnlyAccess permission policy inside ModuleUpdater.
public class Updater : ModuleUpdater {
void ReadOnlyAccesPermissionBehaviour(SecuritySystemRole securitySystemRole, ITypeInfo typeInfo) {
securitySystemRole.SetTypePermissions(typeInfo.Type, SecurityOperations.ReadOnlyAccess, SecuritySystemModifier.Allow);
}
- With the use of XAF’s sub types info API write an abstract algorithm that will enumerate all domain objects and invoke a delegate with same parameters as the method in step 4
public static void CreatePermissionBehaviour(this SecuritySystemRole systemRole, Enum behaviourEnum, Action<SecuritySystemRole, ITypeInfo> action) {
var typeInfos = XafTypesInfo.Instance.PersistentTypes.Where(info => {
var permissionBehaviorAttribute = info.FindAttribute<PermissionBehaviorAttribute>();
return permissionBehaviorAttribute != null && permissionBehaviorAttribute.Name.Equals(Enum.GetName(behaviourEnum.GetType(), behaviourEnum));
});
foreach (var typeInfo in typeInfos) {
action.Invoke(systemRole, typeInfo);
}
}
- Invoke the CreatePermissionBehaviour inside the ModulerUpdater feeding it with the ReadOnlyAccesPermissionBehaviour method of step 4
employersRole.CreatePermissionBehaviour(PermissionBehavior.ReadOnlyAccess, ReadOnlyAccesPermissionBehaviour);
In this post we created reusable algorithms from any XAF projects to help us speeding up the configuration of the initial permissions. When of course talking about code reusability we talk about money saving!
P.S. In a real world application the above coding will be converted to a permission matrix UI representation like,

We would appreciate your feedback on this post. Has it been useful to you? Feel free to contact us with any further questions
Next post will be about what else? its model time!
Happy XAFing as always.


-
DashboardView is a type of XAF View that is used to display several Views side-by-side. However XAF by default does not provide any connection between these Views. In this post, with the help of XAF model, we will discuss a few abstract connection mechanisms and possible uses of dashboards.
Cascading ListViews
In a dashboard, in order to connect the ListViews we need first to connect their models. This can be done using the following interfaces,
public interface IModelDashboardViewFilter : IModelNode {
[DataSourceProperty("FilteredColumns")]
IModelColumn FilteredColumn { get; set; }
[DataSourceProperty("DataSourceViews")]
IModelListView DataSourceView { get; set; }
}
[ModelAbstractClass]
public interface IModelDashboardViewItemEx : IModelDashboardViewItem {
IModelDashboardViewFilter Filter { get; }
}
and then extend XAF’s model, see also our documentation on extending the model
public void ExtendModelInterfaces(ModelInterfaceExtenders extenders) {
extenders.Add<IModelDashboardViewItem, IModelDashboardViewItemEx>();
}
This design allows us to use Model Editor to connect our views. In the following image we see that the selected objects of the Customer_ListView_Calendar are going to filter the Calendar list view on the Receipt.Customer field.

Next we see this dashboard view in action, a SchedulerListEditor on the right is filtered by a GridListEditor,

Following we see this technic applied to 3 ListViews. The selected pie section of the left View filters the pivot which in its turn filters a LayoutListEditor!

Cascading views are as well useful for filtering reports, so by selecting objects on the left View we create a report on the right view and everything is inside a Tabbed MDI environment!

Of course we haven’ wrote the code yet but this is the easy part. XAF’s API is so rich and so well designed that is like we speak our native language! The great thing when XAFing is that our code is fully reusable from any project since it has no knowledge of our domain objects.
Let try to form our requirement in English first:
For each ListView in a Dashboard we need to filter another View when the selection is changed
And now in XAF language
:
protected override void OnViewControlsCreated() {
base.OnViewControlsCreated();
foreach (var result in View.Items.OfType<DashboardViewItem>()) {
var frame1 = result.Frame;
if (frame1 != null && frame1.View is ListView) {
var listView = ((ListView)frame1.View);
DashboardViewItem result1 = result;
listView.SelectionChanged += (sender, args) => OnSelectionChanged(new SelectionChangedArgs(listView, result1));
}
}
void OnSelectionChanged(SelectionChangedArgs selectionChangedArgs) {
var dataSourceListView = DataSourceListView((IModelListView)selectionChangedArgs.DashboardViewItemModel.View);
if (dataSourceListView != null) {
var dashboardViewItems = View.Items.OfType<DashboardViewItem>();
foreach (var dashboardViewItem in dashboardViewItems) {
var modelDashboardViewItemEx = (IModelDashboardViewItemEx)dashboardViewItem.GetModel(View);
FilteredListView(dataSourceListView, dashboardViewItem, modelDashboardViewItemEx);
}
}
Controlling DashboardViewItem visibility
Cascading views are really powerful and soon we will have the need to hide an intermediate view in the chain but being able to filter other views upon it. Therefore we need to add a Visibility property in our model and handle it from our code.
public interface IModelDashboardViewItemEx : IModelDashboardViewItem {
[DefaultValue(ViewItemVisibility.Show)]
ViewItemVisibility Visibility { get; set; }
and in a reusable from all projects controller implement the required logic.
protected override void OnActivated() {
base.OnActivated();
((ISupportAppearanceCustomization)View.LayoutManager).CustomizeAppearance += LayoutManagerOnCustomizeAppearance;
}
void LayoutManagerOnCustomizeAppearance(object sender, CustomizeAppearanceEventArgs customizeAppearanceEventArgs) {
var modelDashboardViewItem = View.Model.Items.OfType<IModelDashboardViewItemEx>().FirstOrDefault(item => item.Id == customizeAppearanceEventArgs.Name);
if (modelDashboardViewItem != null)
((IAppearanceVisibility)customizeAppearanceEventArgs.Item).Visibility = modelDashboardViewItem.Visibility;
}
Displaying HTML Messages
A DashboardView does not have direct dependency with our domain objects. Therefore we can easily use it, even at runtime, to display static text view items and other controls (ControlDetailItem) or images (StaticImage).

XAF has great support for HTML Formatting so a Static Text like “<u><b>Hello</b></u>” will render the following:

Simulating View inheritance
XAF does not support View inheritance however we can extend our model and support it. Lets take the case that we have a very complex listview and we want to display it in both in MasterDetail and ListViewOnly modes without the need to support two View versions. For this we have to extend again the model, this time by a MasterDetailMode property and implement the logic in a ViewController.
[ModelAbstractClass]
public interface IModelDashboardViewItemEx : IModelDashboardViewItem {
MasterDetailMode? MasterDetailMode { get; set; }
public class DashboardInteractionController : ViewController<DashboardView>, IModelExtender {
protected override void OnViewControlsCreated() {
base.OnViewControlsCreated();
ResetMasterDetailModes();
}
void ResetMasterDetailModes() {
foreach (var masterDetailMode in _masterDetailModes) {
masterDetailMode.Key.MasterDetailMode = masterDetailMode.Value;
}
_masterDetailModes.Clear();
}
protected override void OnActivated() {
base.OnActivated();
foreach (var item in View.GetItems<DashboardViewItem>().Select(item => item.GetModel(View)).OfType<IModelDashboardViewItemEx>()) {
AssignMasterDetailModes(item);
}
}
void AssignMasterDetailModes(IModelDashboardViewItemEx modelDashboardViewItem) {
if (modelDashboardViewItem.MasterDetailMode.HasValue) {
var modelListView = modelDashboardViewItem.View as IModelListView;
if (modelListView != null) {
_masterDetailModes.Add(modelListView, modelListView.MasterDetailMode);
modelListView.MasterDetailMode = modelDashboardViewItem.MasterDetailMode.Value;
}
}
}
Since XAF has a great modularization system the core classes/implementations of the above ideas are included in this zip file. However we will not update the contents of the zip file. For locating up to date versions each file in the zip has an OnlineRepoLocation attribute that points to eXpandFramework’s Github repository.
This post adds a few more tools in our development library that can leverage the XAF power using the Model. When we “model” there are three basic advantages:
- We can use these model tools at runtime. For this XAF already provides a runtime time Model Editor.
- We create robust unbreakable code and since we model instead of developing we mostly have no bugs only wrong configuration!
- Implementations are reusable from all our projects!
Next post we will boost our R&D times even further and discuss a bit about Security system policies.
P.S.: We are preparing detailed samples demonstrating all the above ideas
, stay tuned!
If some of you have invented similar ways to connect your dashboards. You can use our support center and share them with the rest of the community.
Happy XAFing!


-
To improve development time and achieve better results we need to use frameworks like XAF. Moreover with XAF it’s really easy to create applications that are maintainable at runtime! After designing a domain model in VS we are almost ready to go. At this point, however we need a smart and flexible importing mechanism for feeding our domain models with initial data. Customers are impressed when they see real world data! So lets build together this mechanism proving once more the XAF power.
Requirements
- Domain model agnostic.
This really means that our importing algorithms should depend only on object types. Therefore we can implement this as an attribute and decorate our domain objects.
- Database agnostic
XPO that supports all common database engines with its rich metadata API is our answer here.
- Flexible mapping configuration
For this we are going to create the an XPO dictionary on the fly. Querying our domain object attributes we can map this dictionary correctly.
- Inheritance mapping configuration
Take as example an Artist, Customer both inheriting a Person object. The attribute should allow to map different the properties of Person when Artist and when Customer.
Examples
- The following example imports all members that belong to MovieArtist from a table with same name columns (AllOwnMembers=true). In addition it maps the oid column in the table of the importing data store to the Oid property of VideoRentalBaseObject (BaseNMembers=”oid|Oid”). Finally it does lookup data in a data store in a table named vMovieArtist (Name=”vMovieArtist”).
[InitialData(BaseMembers = "oid|Oid", AllOwnMembers = true,Name = "vMovieArtist")]
public class MovieArtist : VideoRentalBaseObject {
Artist artist;
Movie movie;
-
The next one imports from a table named CompanyType only the column named Name (AllOwnMembers=false, BaseMembers=null, only Name property is decorated)
[InitialData()]
public class CompanyType : VideoRentalBaseObject {
[InitialData]
public string Name {
get { return _name; }
set { SetPropertyValue("Name", ref _name, value); }
}
-
By default all object relations are auto imported unless the related object is not included in the configuration. Then only the key value is imported. It is also possible to control the mapping in many to many relations as
public class Movie : VideoRentalBaseObject {
[InitialData(DataProviderTableName = "CountryMovies", DataProviderQueryColumnName = "Movies", DataProviderResultColumnName = "Countries")]
[Association("Movies-Countries")]
public XPCollection<Country> Countries {
get { return GetCollection<Country>("Countries"); }
}
The algorithm
- This is an initial data import mechanism. For such operations XAF provides the ModuleUpdater. We need the XafApplication’s IObjectSpace and one UnitOfWork that connects to an external data source so we can simply design an extension method like,
public static void Import(this IObjectSpace objectSpace, UnitOfWork unitOfWork) {
}
and invoke it inside UpdateDatabaseAfterUpdateSchema as,
public class Updater : ModuleUpdater {
public Updater(IObjectSpace objectSpace, Version currentDBVersion) : base(objectSpace, currentDBVersion) { }
public override void UpdateDatabaseAfterUpdateSchema() {
base.UpdateDatabaseAfterUpdateSchema();
var connectionString = ConfigurationManager.ConnectionStrings["initialdata"].ConnectionString;
ObjectSpace.Import(new UnitOfWork{ConnectionString = connectionString});
- Using XAF’s rich reflection API we can enumerate all our domain objects, search for the InitialData attribute and create an XPO dictionary on the fly! This is rather easy as XPO follows a similar to .NET structure, so we have to create XPClassInfo for Classses and XPMemberInfo for members. A great sample exists in our code central so we can get a fast start with this API (E269). Following are the 2 main methods that implement the import mapping.
public static void ImportCore(this IObjectSpace objectSpace, UnitOfWork unitOfWork) {
var builder = new InitDataDictionaryBuilder(objectSpace);
builder.InitDictionary(unitOfWork);
foreach (var persistentTypeInfo in builder.GetPersistentTypes()) {
Import(objectSpace, builder, unitOfWork, persistentTypeInfo);
}
unitOfWork.CommitChanges();
}
internal class InitDataDictionaryBuilder {
public void InitDictionary(UnitOfWork unitOfWork) {
var persistentTypes = GetPersistentTypes();
CreateMemberInfos(unitOfWork.Dictionary, persistentTypes);
}
A complete and up to date version can be found in expandframework’s github repository.
In this post we improved the already rapid XAF development, by creating the import mechanism from almost any type of data into our domain model. In the next one we will visit another great tool offered by XAF the dashboard views.
We would appreciate your feedback on this post. Has it been useful to you? Feel free to contact us with any further questions.
Happing XAFing as always!


-
Our latest poll about supporting multiple branches for both .NET3.5 and .NET4.0 closed a few days ago. The results were in favor of .NET4.0 by 60%. However this was not an election and and the voice of the 40% is clear and loud.
The new coming library we been working on has been refactored to .NET3.5 and in next version 12.1.7.2 we will remove the .NET4.0 dependency from the all other modules. However since our core libs now depend on .NET3.5 we see no reason for supporting 2 branches. We will return to our past branch which contained mixed .NET framework versions. Some modules like Workflow,Quartz, etc have a .NET4.0 dependency some not.
We will run a similar poll in the future to see the size of the minority
. Thanks again everybody for your contribution!


-
Recently we upgraded to .NET4.0. The decision was based on a lib we currently design and will be referenced from the core modules. However it seems that this cause problems to some of you.
Therefore we would like to ask you to participate in the quick survey Dima just published in our site
http://www.expandframework.com/blog.html


-
In order to use an Xpand module up to now we were forced to derive from XpandWinApplication or XpandWebApplication and then register the module using the toolbox. Along with the module functionality however core modules were activated (eg. controllers, updaters, model extensions). These steps are well described in How to use an eXpand module with an existing XAF application.
The process however is not optimal. Many of you already suggested to provide a more flexible and decoupled way. Even if core modules have a huge amount of useful functionality it should be possible to avoid activating them and use only the module that we are interested in.
Good news! From version 12.1.6.5 this is possible and for almost all the modules we do not need to derive from Xpand’s XafApplications. All modules are able to operate without the core however the references back to the core remain. This allows the modules to use the API they need.
There are a few special cases which I will describe them in this forum thread.
P.S.: Those of you that want to learn eXpand news, consider subscribing to the News Forum Category. To get notified about new releases you can follow us on twitter http://twitter.com/eXpandFramework. To watch our daily commits you may subscribe to this github history.


-
April was devoted to improving our continuous integration process. I am happy to announce that eXpand now has a dedicated build server. Many of you already notice its availability in our main download page, the rest are welcome to explore it and get access to all our builds and tests! Teamcity is a great integration platform and for sure will make our dev life easier. Please do not forget to say a big thanks to Dima Janzen since he is our CI guru!


Latest Collaborations
- Import wizard
It is now fully localized! (Big thanks one more time to Martynas Dauciunas) - Master Detail
Controls Disappearing (see http://goo.gl/M9s2g) - Modifications in logic module
To avoid exceptions when view is dashboard (see http://goo.gl/dL8kZ) - Modification in core web module
GridViewOptionsModelSynchronizer incorrectly clears the grid's StatusBar template (see http://goo.gl/eev8H)
As always big thanks for raising your questions and reporting bugs!


-
For March we addressed many bugs and added new stuff taken from your cases. Thank you for participating in our forums!
Latest collaborations
- Option to reload Sequence objects after objectspace commit
Useful in MiddleTier, when server modifies an object. You can enable this attribute via Model/Opetions node see (http://goo.gl/Mvt5Y) - Wizard module (by noxe) ,now has its own place in Xpand’s FeatureCenter. See it in action under DetailViewControls navigation menu. In addition it is possible to show a wizard detail view directly from the navigation menu. Finally there is special support for FocusDefaultDetailViewItemController
- Upgrade to 11.2.10
- Logic modules
Renter bug big thanks to noxe (see http://goo.gl/7f5aW). It is now possible to execute rules when an Action is executed (see http://goo.gl/g2CFT). - Design time errors
BaseimPle Copy local=true exceptions have been minimized now. Each module loads its own objects thus minimizing the references you need from your application project - VS New project Item templates and installer
Martynas and Dima worked on this a lot making sure installer and templates are in a very good shape! - Added generic box implementation as posted in DX forums (see http://goo.gl/Gj9LD big thanks to Alain Bismark )
- ModelDifference
Better support for compile error exceptions (see http://goo.gl/NRxll) - IO
Add missing reference to ModelArtifact state module. - Add commented connection strings for standard authentication with SqlServer (see http://goo.gl/5IS4Z)
- Obsolete SqlDbMapper module
- DBMapper
Support for timestamp database column type for MySql,MsSql,Oracle). In addition MutidataStoreProxy class has one more advantage now, it can operate against legacy databases. Thus DBmapper and WorldCreator can take advantage of this. A new IsLegacy attribute added in PersistentClassInfo to make it possible. Note for the legacy databases inheritance is not supported. - ImportWiz.Win
Martynas worked on various bugs and localization issues. - Addins
Used a modified version of format document on save taken from http://goo.gl/0HCiQ


-
In this post we will discuss how straight forward is to provide a solution for this science fiction subject! Our frameworks (XAF and XPO) along with a few smart classes are fully capable of doing all the hard job and spare our resources. At the end we will be able to apply all the XAF tools / modules in any legacy database. The module can connect the database world with powerful tools like the DX grids. In addition we can use use XAF’s main metadata storage (the model), the security system and all XAF’s modules. These tools are are so powerful that are able to produce logic by themselves! Having such great configuration flexibility it is possible to write behavior after distribution thus you enter new markets and ideas! In addition the module allows you to control the logic after generation using Xaf’s meta driven developing model.
Retrieving any database metadata
XPO is the best candidate for this. since it can transparently talk to more than 15 different database systems!
The metadata API used from XPO to describe its supported databases is very simple as shown,

In a nutshell for each supported database, XPO will return a set of DBTable classes. Each DBTable will be associated with one DBPrimaryKey class and a collection of DBColumn and DBForeighKey classes. Next is the code required to get the DBTable classes out of database and with no surprise again is very simple!
var storeSchemaExplorer = ((IDataStoreSchemaExplorer)XpoDefault.GetConnectionProvider("ConnectionString", AutoCreateOption.None));
var storageTables = storeSchemaExplorer.GetStorageTables(storeSchemaExplorer.GetStorageTablesList());
foreach (DBTable dbTable in storageTables) {
foreach (DBColumn dbColumn in dbTable.Columns) {
//now we are ready to do magic!
}}
Connecting at runtime – The magic part
In order to query and create CRUD operations for a database system XPO requires a set of business classes. However, now there is a runtime factor involved. We need to create these business classes dynamically.
XAF’s modularized architecture made this task too easy for us! We already created a dynamic class generation module called WorldCreator in the past. WorldCreator maps the structure of an assembly into persistent classes.

What we need is for each database to create a new PersistentAssemblyInfo, then for each DBTable a new PersistentClassInfo and finally for each DBColumn a new PersistentMemberInfo. In pseudo code this will look like,
var persistentAssemblyInfo = ObjectSpace.CreateObject<PersistentAssemblyInfo>();
foreach (DBTable dbTable in storageTables) {
var persistentClassInfo = ObjectSpace.CreateObject<PersistentClassInfo>();
persistentAssemblyInfo.Name = dbTable.Name;
persistentAssemblyInfo.PersistentClassInfos.Add(persistentClassInfo);
foreach (DBColumn dbColumn in dbTable.Columns) {
var persistentMemberInfo = ObjectSpace.CreateObject<PersistentMemberInfo>();
persistentMemberInfo.Name = dbColumn.Name;
persistentClassInfo.OwnMembers.Add(persistentMemberInfo);
}
}
WorldCreator UI allows further extension of the model as simple as writing .NET code or creating new objects. More ideas and contributions are always welcome.
Up to this point everything was extremely easy for us and almost shocking in terms of productivity! I believe there is no reason to change that feeling so lets move to our final task.
WorldCreator is simply a code generation module. It generates assemblies which include XAF modules and loads them at application startup. However that assembly has no difference at all from the assemblies we create at design time. The persistent classes of this dynamic module belong and point back to main XAF database. What we want here is to redirect the generated sql statements back to the original mapped database.
Once more we have most of the job ready! eXpand already uses a proxy version of ObjectSpaceProvider to support scenarios similar to show Business Classes from several databases in a XAF application. Thus associating a WordCreator assembly (set of business classes) with a database is a rather easy job.
Connecting to any database at runtime at first sounded very complicated. However our frameworks proved once more that they can raise our productivity and make our jobs so simple that even such complex task can fit in a small post like this one.
The new module DBMapper, is already released as part of eXpand framework’s modules collection.
We would appreciate your feedback on this post. Has it been useful to you? Feel free to contact us with any further questions.


-
We appreciate your support and efforts in raising issues that help stabilizing our framework! This list is of what we have managed within February.
Latest Collaborations
- Fixed bugs with SequenceGenerator and MiddleTier
http://goo.gl/qhzwk - Foreign key feature violations
http://goo.gl/Mha6S - Provided association bug with Domain components
- Upgrade to 11.2.8
- Fix Jobscheduler initialization, causing thread keeping alive.
http://goo.gl/LFUpa - Modeldifference model combing exception
http://goo.gl/Qq03J - Master detail should tamper only states of actions in ViewController
- Clear build warnings
- ConditionalDetailView support for ViewShowing Execution context. This make it possible to have conditional view when creating a new object.
http://goo.gl/5iKrM


-
Although a bit outdated its better to publish it now than never. Your eXpand collaborations never stop, so it’s a shame to keep them secret from the rest of the community.
Latest Collaborations
- Logic modules(AdditionalViewControlsProvider, MasterDetail, ConditionalDetailViews, ModelArtifact) as well as ModelDifference, PivotChart were migrated to the new XAF security system. The new custom permissions are located under the Security.Improved namespace in each module.
- Out of the box support for support for CachedDataStoreService (see also http://goo.gl/BtYxw)
- Minor bugs in MasterDetail, PivotChart, ExceptionHandling
- An eXpand based version of SecurityDemo solution added to our sources.
- AdditionalViewsControls now have better support for custom controls (see also http://goo.gl/SyvOz)
- eXpand has build in support for Sequence objects and we make it possible to to use a custom one.
- In addition to the big list of runtime member types we added a new custom member type, which allows to specify an callback which is called in the getter of the member (Thanks to Martin Praxmarer)
- MasterDetail now supports validation of child list view objects (Thanks to Martin Praxmarer)
Thank you all for your contributions! Lets work closer together in 2012 and give even more value to our beloved frameworks!


-
Friends asking me what are you doing man? I usually answer back: busy busy busy. They usually respond with a phrase like: Busy is good it means that you are doing great!
Latest Collaborations
- Our MSI package now installs VS New Project Item templates and sources. (Thanks to Dima Janzen!)
- Several bugs due to improved Security system support
- SqlDBmapper now support different database schemas (see also http://goo.gl/qSj4B)
- DomainComponent support for Logic Modules
- Bugs in the core modules (LinqCollectionSource,ChooseFromListCollectionEditor) (http://goo.gl/dqMRG, http://goo.gl/q2SFE)
- Middle Tier support for our new custom permissions for the improved security system (http://goo.gl/k9Gh1)
- New module release: DBMapper has the same functionality as SqlDbMapper however is based on the powerful XPO. Thus this module is capable of transforming into WorldCreator persistent classes the following list of databases: Access, Advantage, Adaptive Server Anywhere, Ase, DB2, FireBird, FireBirdSql, SqlServerCe, SqlServer, ODP,
Oracle, PersasizeSql, PostgreSql, SQLite, VistaDB


-
LINQ is .NET Language-Integrated Query. It's included in .NET Framework 3.5 and you can use it in Visual Studio 2008 projects. XPO has officially supported LINQ since v7.3 and since then we have continued to improve and support it. Nowadays LINQ to XPO is very mature, extendable (How to: Implement Custom Functions and Criteria in LINQ to XPO) and powerful (Free Joins). In the latest version we make it even easier to use LINQ to XPO since we only distribute one assembly, DevExpress.XPO.dll, which includes everything! (custom providers as well).
XPO can talk transparently to a large list of database systems. It was already possible to make complex queries using our standard criteria syntax, however using LINQ offers some great advantages.
- No magic strings, like you have in standard criteria syntax,
- Intellisense support making it easier and faster to construct your queries,
- Compile time checking,
- Learning to write LINQ queries/lambdas is a must learn for .NET developers,
The benefits are clear, however there is a caveat when using LINQ. It is not possible to use Edit and Continue and with even the smallest change you need to restart your debugging session. As a result your development speed is decreased dramatically.
The solution as always is to use the right tool and in this case the right tool is LINQPad. It provides a flexible UI allowing you to use LINQ in various ways.
In our latest version our team released an XPO context driver for LINQPad. Let’s see how to configure it.
Firstly we need to install the driver found at C:\DevExpress 2011.2\Components\Tools\DXperience\XPOContextDriver.lpx.

Secondly we need to setup a new connection.

In this example we are going to use the MainDemo assembly containing the business objects.

LINQPad populated the domain in a hierarchical treelist. This allows us to enjoy using drag & drop plus intellisence in its expression editor to form the LINQ queries. Furthermore it is possible to use your style of language as demonstrated below.

The cool part is that LINQPad, written by the great Joe Albahari, is available for free. It is strongly recommended as a great way to learn LINQ.
Now for the fun part, let’s see it in action. Imagine we have the following code in our VS.
var queryable = from c in contacts
let tasks = c.Tasks.Where(t => t.ActualWork < 0)
where tasks.Any()
orderby c.LastName
select new {
c.LastName,
Orders = tasks.Count(),
};
We wish to see the results of queryable variable ,the best way to achieve this is to set a breakpoint then hit F5. Next we wait for our app to load and navigate to the action that will hit the breakpoint. Finally we must select the queryable variable and hit Shift+F9 to invoke the debugger window and examine the result set. Now we can try to make our requirements more complex. Lets say we also want to examine the result set when ActualWork>10. The solution is really easy when using LINQPad, we simply need to copy paste the code from VS to LINQPad the expression editor like this,

After this we can quickly and easily form queries as we wish and examine their result sets instantly. Using the excellent and cheap LINQPad Autocompletion it is possible to use VS like intelligence to further speed up your development.

PS: eXpandFrameWork contributors are already using the Autocompletion feature since LINQPad offered a license for its contributors.
We would appreciate your feedback on this post. Has it been useful to you? Feel free to contact us with any further questions


-
Just a quick post to wish all of you out there in the community a very Merry Christmas and a Happy New Year! I thought I had better take some time out from all the usual revelry to thank you all for making our framework what it is right now. Now is the season of generosity and goodwill so it's a good time to reflect on what has been achieved at eXpand through the giving of ideas. Of course my biggest Christmas wish is that communication and collaboration between us all in the online community is increased a thousand times more! Let's all make a New Year's resolution to work together and take our framework to the roof!
MERRY XMAS!


-
At 11.00 PST on Thursday 15th December I will be appearing live on Scott Hanselman’s podcast Hanselminutes. During the course of the show Scott and I will be discussing eXpand framework and its relationship with XAF. Please tune in and show some support for your favorite frameworks! We built this thing together guys and this is an exciting event for all of us.


-
WF4 uses a service oriented architecture and as a result any problem can be decoupled into smaller, easily solvable and testable services. XAF uses MVC architecture which, in a sense, is very similar to that used by WF4. We can compare XAF’s controllers to WF4 services. Moreover XAF’s Application does the same job as the WF4 server. The upshot of all this is that users should be able to get the feel of WF4 in no time at all. The XAF workflow module introduces a new layer that makes the already decoupled services aware of our business classes. After this the sky is the limit and over the next few posts I aim to demonstrate some of what can be achieved. For example the next post will focus on creating an event driven workflow initialization engine.
To get back to today’s post, we will discuss an implementation that is very decoupled and as a result it has very limited dependencies on other modules. It is worth noting that all XAF’s features are decoupled, persistent objects take on the role of domain mappers.
Take these requirements;
- an end user needs to be able to input an object type (and or) a property name,
- an object change needs to start the workflow either at client or at sever,
- workflows need to be aware of the object that has changed, its PropertyName and its property OldValue.
The custom workflow definition
We cannot use the default XAF XpoWorkFlowDefinition class in any way. This is because there are no fields to store the PropertyName and its OldValue. We should not even derive from the default XpoWorkFlowDefinition because we may face difficulties as this class is used by our workflow server. To cope with this issue it is necessary to create a custom ObjectChangedWorkflow definition as shown.

While we are doing this we also need to modify the default xaml of the workflow and add the two more arguments (propertyName, oldValue) as per our requirements.

Below you can see the UI of this custom workflow definition,

Up to here XAF has made things very straightforward for us. We have designed a normal persistent class to store our data and we have used attributes (PropertyEditorType, DataStourceProperty, TypeConverter etc) to configure the UI.
Registration of custom workflow definition
The next step is to register this custom workflow definition. To help with this task, eXpand, provides the WorkflowStartService<T> where T is the type of workflow. Furthermore for ObjectChangeWorkflow definitions the implementation is rather easy since there are no further requirements.
public class ObjectChangedWorkflowStartService : WorkflowStartService<ObjectChangedWorkflow> {
public ObjectChangedWorkflowStartService()
: base(TimeSpan.FromMinutes(1)) {
}
public ObjectChangedWorkflowStartService(TimeSpan requestsDetectionPeriod) : base(requestsDetectionPeriod) { }
protected override bool NeedToStartWorkflow(IObjectSpace objectSpace, ObjectChangedWorkflow workflow) {
return true;
}
protected override void AfterWorkFlowStarted(IObjectSpace objectSpace, ObjectChangedWorkflow workflow, Guid startWorkflow) {
}
}
Start workflow - Track Object Changes
Now, when I have registered workflows on the server, it's time to return to my task: start a workflow when a property has been changed.
In XAF, I can track changes with the help of the ObjectSpace.Committing and ObjectSpace.ObjectChanged events. However because we need to create only one request per object change, it is advisable to collect the changes in an array.
public class StartWorkflowOnObjectChangeController : ViewController<ObjectView> {
protected override void OnActivated() {
base.OnActivated();
if (TypeHasWorkflows()) {
ObjectSpace.ObjectChanged += PopulateObjectChangedEventArgs;
ObjectSpace.Committing += StartWorkFlows;
}
}
void PopulateObjectChangedEventArgs(object sender, ObjectChangedEventArgs objectChangedEventArgs) {
if (!string.IsNullOrEmpty(objectChangedEventArgs.PropertyName)) {
var changedEventArgs = _objectChangedEventArgses.FirstOrDefault(args => args.Object == objectChangedEventArgs.Object && args.PropertyName == objectChangedEventArgs.PropertyName);
if (changedEventArgs != null) {
_objectChangedEventArgses.Remove(changedEventArgs);
_objectChangedEventArgses.Add(new ObjectChangedEventArgs(changedEventArgs.Object, changedEventArgs.PropertyName, changedEventArgs.OldValue, objectChangedEventArgs.NewValue));
} else
_objectChangedEventArgses.Add(objectChangedEventArgs);
}
}
void StartWorkFlow(ObjectChangedEventArgs objectChangedEventArgs, ObjectChangedWorkflow objectChangedWorkflow) {
var o = objectChangedEventArgs.Object;
ITypeInfo typeInfo = XafTypesInfo.Instance.FindTypeInfo(o.GetType());
object targetObjectKey = typeInfo.KeyMember.GetValue(o);
if (objectChangedWorkflow.ExecutionDomain == ExecutionDomain.Server) {
CreateServerRequest(objectChangedEventArgs, objectChangedWorkflow, targetObjectKey, typeInfo);
} else {
InvokeOnClient(objectChangedEventArgs, objectChangedWorkflow, targetObjectKey);
}
}
As you will have noticed we have not used the default VS naming for ObjectSpace event handlers. This is because the names that have chosen give a more specific idea of how each method works.
The ObjectChanged event occurs each time a property is changed and the changes are collected in the objectChangedEventArgses array. The Committing event occurs once changes are ready to be sent to the server and workflows start for each entry. We have introduced two options for starting and executing workflows;
- Execute synchronously and locally,
- Send a request to the server and execute at the server asynchronously
Execute a workflow synchronously on the client
The next stage is to create activities at the client then on ObjectSpace CommitChanges from appropriate WorkflowDefinition and execute them immediatelly
public class StartWorkflowOnObjectChangeController : ViewController<ObjectView> {
void InvokeOnClient(ObjectChangedEventArgs objectChangedEventArgs, ObjectChangedWorkflow objectChangedWorkflow, object targetObjectKey) {
Activity activity = ActivityXamlServices.Load(new StringReader(objectChangedWorkflow.Xaml));
var dictionary = ObjectChangedStartWorkflowService.Dictionary(targetObjectKey, objectChangedEventArgs.PropertyName, objectChangedEventArgs.OldValue);
WorkflowInvoker.Invoke(activity, dictionary);
}
This is a simple code which can be found in nearly any WF4 example at
http://www.microsoft.com/download/en/details.aspx?id=21459.
Send a request to start workflow on the server
The second of our two methods involves starting the workflow at the server. Now we need to notify the server of the values of those arguments as well. In the manually starting workflows post we learnt that XAF does this by using XpoStartWorkflowRequest. This class has a different design however, and may create issues since it is used by XAF default services. Therefore instead of deriving from XpoStartWorkflowRequest we need to design a similar custom class.
public class ObjectChangedXpoStartWorkflowRequest : WFBaseObject, IObjectChangedWorkflowRequest {
[TypeConverter(typeof(StringToTypeConverter))]
public Type TargetObjectType {
get { return _targetObjectType; }
set { SetPropertyValue("TargetObjectType", ref _targetObjectType, value); }
}
#region IDCStartWorkflowRequest Members
public string TargetWorkflowUniqueId {
get { return GetPropertyValue<string>("TargetWorkflowUniqueId"); }
set { SetPropertyValue("TargetWorkflowUniqueId", value); }
}
[ValueConverter(typeof(KeyConverter))]
public object TargetObjectKey {
get { return GetPropertyValue<object>("TargetObjectKey"); }
set { SetPropertyValue<object>("TargetObjectKey", value); }
}
#endregion
#region IObjectChangedWorkflowRequest Members
public string PropertyName {
get { return _propertyName; }
set { SetPropertyValue("PropertyName", ref _propertyName, value); }
}
[ValueConverter(typeof(SerializableObjectConverter))]
[Size(SizeAttribute.Unlimited)]
public object OldValue {
get { return _oldValue; }
set { SetPropertyValue("OldValue", ref _oldValue, value); }
}
This is a very simple class, its only role is to store values in the database. Now instead of invoking workflows locally we only need to create ObjectChangedXpoStartWorkflowRequest objects.
public class StartWorkflowOnObjectChangeController : ViewController<ObjectView> {
void CreateServerRequest(ObjectChangedEventArgs objectChangedEventArgs, ObjectChangedWorkflow objectChangedWorkflow, object targetObjectKey, ITypeInfo typeInfo) {
var request = ObjectSpace.CreateObject<ObjectChangedXpoStartWorkflowRequest>();
request.TargetWorkflowUniqueId = objectChangedWorkflow.GetUniqueId();
request.TargetObjectType = typeInfo.Type;
request.TargetObjectKey = targetObjectKey;
request.PropertyName = objectChangedEventArgs.PropertyName;
request.OldValue = GetOldValue(objectChangedEventArgs);
}
In the next step we are going to create a service to consume these values from the server and start a workflow,
public class StartWorkflowOnObjectChangeService : BaseTimerService {
public override void OnTimer() {
using (var objectSpace = ObjectSpaceProvider.CreateObjectSpace()) {
//get all requests from the database
foreach (var request in objectSpace.GetObjects<ObjectChangedXpoStartWorkflowRequest>()) {
//find workflow
var definition = GetService<IWorkflowDefinitionProvider>().FindDefinition(request.TargetWorkflowUniqueId);
if (definition != null && definition.CanOpenHost) {
//Start the workflow passing in PropertyName && OldValue
if (GetService<ObjectChangedStartWorkflowService>().StartWorkflow(definition.Name,
request.TargetWorkflowUniqueId, request.TargetObjectKey, request.PropertyName, request.OldValue)) {
objectSpace.Delete(request);
objectSpace.CommitChanges();
}
}
}
}
}
At this point our server has all the information it needs to start workflows with arguments taken from persistent ObjectChangeXpoStartWorkFlowRequest objects.
I must admit that I have fully enjoyed preparing this post. The decoupled development experienced offered by the WF service oriented model is something that really appeals to me. At the same time XAF’s workflow module implementation made modeling the requirements a simple and enjoyable process. As usual it was possible to work directly on the problem and leave the hard work to non XAF developers.


-
The last few months have been exciting here at eXpand. First and foremost the number of you that are contributing to the project has shot up which is great news for all of us! Also (as some of you may have noticed) we have earned ourselves a place in the DevExpress start menu. There has been a flurry of activity on the development side too, as a result we are pleased to offer a host of innovative new features. Finally eXpand is now registered at http://nuget.org/ so it can be accessed via Visual Studio.
Contributors!
First of all we must all say a big thank you to everybody that has been contributing to eXpand in any way. We appreciate your continuing love and support whether in the form of forum posts, code submissions, user suggestions or simply spreading the good word about eXpand! Our community is very healthy right now, I am proud of the fact that eXpand users are collaborating more than ever and sharing their ideas and stories.
Of course at the same time we must thank DevExpress for their steady support and the trust that they have placed in eXpand. By allowing eXpand a place in their start menu it’s not even easier for us to share our framework with other XAF developers.
To all those who are ready to take the leap and start contributing to our framework I can promise that being part of our community means a full share in all of the benefits. Of course the more we all contribute the more benefits there will be!
Latest Collaborations
I could talk about new features here, however I have deliberately chosen the word ‘collaborations’ in recognition of the fact that these developments are a direct result of your contributions to eXpand. It is clear that to list all of our collaborations here would take too long, but lets take a look at some of the most successful so far;
- Masterdetail
Offers support for actions state synchronization between master detail frames.
- LayoutViewGridListEditor
Enables LayoutView mode in the GridControl in List Views as in E1486.
- Setup version
In order to make distinguishing between versions easier we have used a version dedicated name for our setup.
- Wizard
Offers support for domain components.
- Caching support
Enables caching at client and server by using a setting in the application config file.
- Toolbox
When compiling our sources all eXpand assemblies will be auto registered to VS toolbox.
What's next?
More modules that will prove the simplicity and power of XAF from dedicated coders. In addition we are redesigning our site in order to establish better collaboration with all of you. We see this as an opportunity through XAF modularized architecture to share our experiences in order to give our business more relaxed weekends. We believe that with your help our job will become much easier, especially since DX is also here to guide us!


-
Prerequisites
Part 1
In this post we are going to enhance the State Machine module UI. Remember that along with all the usual XAF goodies we can now use Xpand code base which gives us a lot more options. Our StateMachineTransitionPermission has 2 lookups, StateMachineName and StateMachine. Our goal is to populate both of these cascading lookups without creating a platform specific module.
StateMachineNames
Creating lookups is a common scenario for which Xpand provides a set of property editors and controllers. By contrast with other business frameworks XAF allows maximum flexibility. Therefore in most cases we are able to code in such a generic way that everything could live in separate frameworks such as eXpand. Now, in order to populate the StateMachine name I am going to derive a new controller from a specialized abstract controller which is Xpand.ExpressApp.SystemModule.PopulateController<T>. This controller uses the PredefinedValues attribute of the XAF model. When filling the attribute with a set of values separated by semicolons XAF will create a lookup with these values targeting each supported platform.

However, if at runtime we set the value of the PredefinedValues attribute this will be written at model’s lastlayer and it will make it dirty. We want to avoid this because we want to leave the lastlayer intact.. To cater for this need the populate controller uses a hack. First it stores the lastlayer in a variable then removes it from the model’s layers collection. As a result it is possible to modify the new lastlayer as shown in the Populate method and then return the clean old one to its place. Now the model has all the necessary information with a clean userdiffs layer and while XAF is creating a new view can get the PredefinedValues string from it and create the lookups.
public abstract class PopulateController<T> : ViewController<ObjectView> {
…
…
protected virtual void Populate(Func<IModelMember, string> collect) {
var name = PropertyName;
if (name != null) {
var model = ((ModelApplicationBase)Application.Model);
var lastLayer = model.LastLayer;
model.RemoveLayer(lastLayer);
PopulateCore(collect, name);
model.AddLayer(lastLayer);
}
}
private void PopulateCore(Func<IModelMember, string> collect, string propertyName) {
IModelMember modelMember = View.Model.ModelClass.AllMembers.FirstOrDefault(member => member.Name == propertyName);
if (modelMember != null) {
modelMember.PredefinedValues = collect.Invoke(modelMember);
}
}
…
…
}
Although this seems like a complicated explanation users need not be intimidated! The implementation of our controller that will populate all StateMachineNames is as simple as this,
public class StateMachinePopulateController : PopulateController<StateMachineTransitionPermission> {
protected override string GetPredefinedValues(IModelMember wrapper) {
IList<XpoStateMachine> xpoStateMachines = ObjectSpace.GetObjects<XpoStateMachine>(null);
return xpoStateMachines.Select(machine => machine.Name).AggregateWith(";");
}
protected override Expression<Func<StateMachineTransitionPermission, object>> GetPropertyName() {
return permission => permission.StateMachineName;
}
}
The first thing we did was to provide the propertyName in the GetPropertyName method. Then using the GetPredifinedalues method we return the semincolon delimited string with the machine names. This very simple controller is capable of populating the statemachine lookup for win and web platforms!.
StateCaptions
This is a cascading lookup and as a result when the current StateMachineName changes it needs to provide a list of all its StateCaptions. To this end we are going to use a specialized property editor, Xpand’s StringLookupEditor. This supports the
DataSourceProperty XAF attribute which will be used to provide the StateCaption collection. Moreover when using Xpand it is possible to mark editors with an interface and host it in a transparent module. We can then use the Xpand PropertyEditor attribute with the type of the interface as parameter to tell XAF which propertyeditor will be created at runtime. Finally we need to apply all these along with an ImmediatePostData to the StateMachineName property. The permission will look like this,
[ImmediatePostData]
public string StateMachineName { get; set; }
//IStringLookupPropertyEditor lives in Xpand.ExpressApp assembly
//Xpand.ExpressApp.Web.PropertyEditors.StringLookupPropertyEditor, Xpand.ExpressApp.Win.PropertyEditors.StringLookupPropertyEditor inherit from IStringLookupPropertyEditor
[PropertyEditor(typeof(IStringLookupPropertyEditor))]
[DataSourceProperty("StateCaptions")]
public string StateCaption { get; set; }
IList<string> _stateCaptions = new List<string>();
[Browsable(false)]
public IList<string> StateCaptions {get {return _stateCaptions;}}
If you look carefully at this code however you may notice that __stateCaptions count is always zero. Let me remind you here that the StateMachineTransitionPermission is a non persistent sessionless object. This means that the object is not handled by an ObjectSpace therefore a call like ObjectSpace.FindObjectSpaceByObject(this) will always return null. In addition the permission does not implement INotifyPropertyChanged so we need to synchronize the class just before the StateCaptions are requested. Below you can see a modified version of the StateMachinePopulateController,
public class StateMachinePopulateController : PopulateController<StateMachineTransitionPermission> {
protected override void OnViewControlsCreated() {
base.OnViewControlsCreated();
var stringLookupPropertyEditor = GetPropertyEditor(permission => permission.StateCaption) as IStringLookupPropertyEditor;
if (stringLookupPropertyEditor != null)
stringLookupPropertyEditor.ItemsCalculating += StringLookupPropertyEditorOnItemsCalculating;
}
void StringLookupPropertyEditorOnItemsCalculating(object sender, HandledEventArgs handledEventArgs) {
var propertyEditor = GetPropertyEditor(permission => permission.StateMachineName);
if (propertyEditor != null && View.IsControlCreated) {
var stateMachineTransitionPermission = ((StateMachineTransitionPermission)View.CurrentObject);
var readOnlyCollection = GetStateCaptions(propertyEditor);
stateMachineTransitionPermission.SyncStateCaptions(readOnlyCollection, propertyEditor.ControlValue as string);
}
}
ReadOnlyCollection<string> GetStateCaptions(PropertyEditor propertyEditor) {
var stateMachineName = propertyEditor.ControlValue as string;
return ObjectSpace.GetObjects<XpoState>(state => state.StateMachine.Name == stateMachineName).Select(
state => state.Caption).ToList().AsReadOnly();
}
Finally we add the new SyncStateCaptions method and the full version of the permission will be,
[NonPersistent]
public class StateMachineTransitionPermission : PermissionBase {
…
…
[ImmediatePostData]
public string StateMachineName { get; set; }
[PropertyEditor(typeof(IStringLookupPropertyEditor))]
[DataSourceProperty("StateCaptions")]
public string StateCaption { get; set; }
IList<string> _stateCaptions = new List<string>();
[Browsable(false)]
public IList<string> StateCaptions {get {return _stateCaptions;}}
public void SyncStateCaptions(IList<string> stateCaptions, string machineName) {
StateMachineName = machineName;
_stateCaptions = stateCaptions;
}
}
To support platform independent cascading lookups we wrote only about 10 lines of code! This is proof of how much XAF architecture cuts down on development costs. The module can be downloaded from the Xpand download page and we are happy to hear your feedback. Remember that your questions are the best candidates for future posts!


-
As promised in the previous post I will now attempt to provide a concise yet comprehensive look at the 5 possibilities that Xpand gives us when we want to create a calculated member. I will also provide discussion of the relative advantages and disadvantages of each approach. We can see all of them in action in Xpand FeatureCenter application. Remember it is only thanks to the fact that XAF/XPO have such a strong and flexible architecture that this is possible! We must also acknowledge that these approaches have evolved as a direct result of contributions from the XAF team and community.

1. The XPO way –>Using Code
Take a look at the CreateCalculabeMember extension method in the code below,
public class CreateRuntimeCalculatedFieldController : ViewController {
public override void CustomizeTypesInfo(DevExpress.ExpressApp.DC.ITypesInfo typesInfo) {
base.CustomizeTypesInfo(typesInfo);
XPClassInfo classInfo = XafTypesInfo.XpoTypeInfoSource.XPDictionary.GetClassInfo(typeof(Customer));
if (classInfo.FindMember("SumOfOrderTotals")==null) {
var attributes = new Attribute[] {new PersistentAliasAttribute("Orders.Sum(Total)")};
XPCustomMemberInfo calculabeMember = classInfo.CreateCalculabeMember("SumOfOrderTotals", typeof(float), attributes);
typesInfo.RefreshInfo(typeof(Customer));
}
}
}
XPO has a dictionary of domain metadata. The metadata of each persistent object is stored in XPClassInfo classes and the metadata of their properties is stored in XPMemberInfo classes. One of the main advantages of this approach is that it adds a new member to the XPO dictionary and therefore follows XAF to the letter. This is because in order to form the model XAF first queries the XPO dictionary and finally in order to configure the views it queries the model. Since we have worked in the data layer our calculated values will be sent to any data bound enabled control for rendering. The other benefit is that if we code there are no restrictions on what we can do, for example we can create members calling a WCF service. The sky’s the limit!
On the other hand each time we write new code we need to spend time testing and distributing it. Furthermore in certain scenarios problems can occur due to the fact that we add a new member to the object. For each new member we add to an object we are forced to deal with long properties lists in our model which can be somewhat unwieldy – imagine an object with 200 properties.
Note; XAF is smart enough to manage all of this without even breaking a sweat. This means that its performance does not suffer in any way. It is simply that this approach can leave the user with a bit of a headache!
2. Using the model
We have extended our model in order to describe all types of calculated and runtime properties.

Having done this makes it pretty easy to utilize the powerful XPO and add members in its dictionary as with the previous approach. This means this method shares some of the benefits we mentioned above. However as we are not writing code we can’t enjoy the same level of flexibility unless we utilize ModelUpdaters. Also as the columns can only be created using model editor they are only useful in situations when we have permission to modify the model. Finally we could end up with a huge number of properties here too for the same reason we identified previously.
All this is not to say that this approach doesn’t have its own unique advantages. For example the model difference can be stored in a database or xml file making it easy to distribute. To this end we can use the build in API or a specialized module like IO. Moreover it is possible to develop on site (client). Of course working at the model level allows us to use a model manager module like ModelDifference which is a great aid. It can be used to distribute the unbound columns to users, roles and even to other applications. In addition since ModelDifference supports both platforms it is possible to create calculated members without restarting the application or IIS.
3.WorldCreator extended members
This module maps the structure of the XPMemberInfo class to a persistent object. This approach is again similar to model approach (and once again has similar benefits) however there is a crucial difference. Instead of using the model to gather data to form the calculated members we use the input taken from the UI.


Using the UI is simplicity itself! It requires no technical knowledge whatsoever as the user is only required to choose from a set of basic options. We can still code if we wish, this time by creating persistent objects and then leaving eXpand to take care of the rest. That being said the real beauty of this approach is that the product can be developed on site without the user having to write a single line of code or using a sophisticated tool like Model Editor. Moreover we can enjoy ease of distribution due to the fact that our objects are stored in the database. As the metadata is now in the form of persistent objects locating it and working with it is as easy as ever.
By now it should be clear that as we are still relying on XPO we are faced with the same old problem regarding multiple views.
4. Using a WordCreator Dynamic Assembly
Our fourth approach uses the same module to create dynamic persistent assemblies using code generation templates. XAF is the best framework to describe domains which is evidenced by the way that WorldCreator maps the Assembly structure to persistent objects and auto generates a flexible UI.

Using the templates will create a dynamic assembly with exactly the same code and structure as if we had taken the time to design it ourselves inside VS. Distribution is still easy since is everything is in the database. The fact that we script at runtime means that our options are almost unlimited when taking this approach.
5. The Unbound Column
Extending the model with an Unbound column node as shown makes it possible to create Unbound grid columns and set their unbound expressions.


This is the only approach that allows us to work directly on views without utilizing XPO. This means that we gain the maximum level of flexibility since it is possible to have different columns for the same object views. Therefore we can work on this column independently. At the same time the end user can change the UnboundExpression at runtime using expression editor (windows only). When it comes to distribution we find the same advantages as we do whenever we deal with the model.
As with the second approach we lose some flexibility because we are not writing code but again we can get round this using ModelUpdaters. In addition our columns still cannot be used when we do not have permission to modify the model. Another disadvantage concerns the fact that XAF is designed to make all calculations in the data layer and send the values to controls by applying an MVC pattern. A few years after XAF was released, Microsoft built Silverlight featuring very similar architecture. Taking into account the various factors this has been recognized as the optimal approach. Although using Unbound columns allows us to work in a different way we need to write extra code to support each control (Tree, Pivot etc) because the calculations are performed in the UI.
We are happy to read your feedback about this!. Remember that your questions are the best candidates for future posts.


-
Recently in Xpand forums Dionisis Soldatos raised a question about how unbound columns can be implemented with XAF. Unbound columns along with their UnboundExpression can be used for creating calculated fields even at runtime. Since we are talking about unbound grid columns it should be obvious that we will operate at the UI level by modifying the grid control columns. However lets do a deep dive inside XAF model to extend it as needed!
The Model
By now we are all used to XAF providing us with excellent out of the box solutions which negate the need for us to write hundredths of lines of code. This of course means money saved during developing and ultimately your product hits the market faster. Why spend time reinventing the wheel when the XAF team have already done the hard work for you?
XAF creates the model by reading the metadata of our classes, this model has 3 types of view. One of these is the ListView which can be displayed with data source enabled controls like Grid controls. ListView has columns which correspond to existing object properties metadata and when XAF creates a Grid at runtime it queries model’s ListView columns. It then creates and configures Grid columns from their attributes. These stages are well tested and it is preferable to use them in our solution and override the unnecessary stages. For example we could create a normal model column node using XAF default Add/Column menu. After the Grid column is created it we simply need a few lines of code to make it unbound and set its Unbound Expression.

In order to store this expression we still need to extend model’s ListView with an attribute. The model can be extended either by registering an interface at ModuleBase.ExtendModelInterfaces or by deriving it from an already registered interface. I am going to take the latter options by deriving from IModelColumn interface which I will explain as we go.
public interface IModelColumnUnbound : IModelColumn {
[Category("eXpand")]
bool ShowUnboundExpressionMenu { get; set; }
[Category("eXpand")]
[Required]
string UnboundExpression { get; set; }
}
XAF model editor is a highly sophisticated tool which has the capability to recognize that we extended the model. It then takes care of the vital step of adding an entry to the Add menu for creating Unbound columns.

Now it is possible to create a new type of column with 2 extra attributes as shown,

Moving on we need to set the mandatory PropertyName attribute shown above to an always existing object property name. Remember XAF requires this in order to behave as designed. To this end we are going to set as PropertyName the object’s key property name using this simple DomainLogic class,
[DomainLogic(typeof(IModelColumnUnbound))]
public class IModelColumnUnboundLogic {
public static string Get_PropertyName(IModelColumnUnbound columnUnbound) {
return ((IModelListView)columnUnbound.Parent.Parent).ModelClass.KeyProperty;
}
As a result (PropertyName, PropertyEditorType and Caption) attributes will be populated the next time we create a ColumnUnbound Node. However these will be fixed values and it is preferable to hide them from the end user. At the same time we need to mark Caption attribute as required and remove its default value. To do all of this we just need to extend our IModelColumnUnbound interface like this,

Note; Although PropertyName and Caption belong to IModelColumn using the new operator it is possible to override them!
We have now finished with the model modifications and for our ColumnUnbound nodes XAF by design will create a new column pointing back to object’s key property metadata.
The UI
A key benefit of XAF’s commitment to design patterns, specifically to the Single responsibility principle, is that it provides us with the model’s synchronizer classes. These can be used to synchronize our model with the control and vice versa. It is only necessary to derive from the abstract ModelSyncroniser<T,V> and implement ApplyModeCore method to synchronize the control and from SynchronizeModel to do the same with the model.
public class UnboundColumnSynchronizer: ModelSynchronizer<GridListEditor, IModelListView> {
public UnboundColumnSynchronizer(GridListEditor control, IModelListView model)
: base(control, model) {
}
protected override void ApplyModelCore() {
var xafGridColumns = GetXafGridColumns();
foreach (var column in xafGridColumns) {
var modelColumnUnbound = (IModelColumnUnbound)column.Model;
column.FieldName = modelColumnUnbound.Id;
column.UnboundType = UnboundColumnType.Object;
column.OptionsColumn.AllowEdit = false;
column.ShowUnboundExpressionMenu = modelColumnUnbound.ShowUnboundExpressionMenu;
column.UnboundExpression = modelColumnUnbound.UnboundExpression;
}
}
IEnumerable<XafGridColumn> GetXafGridColumns() {
IEnumerable<XafGridColumn> xafGridColumns =
Model.Columns.OfType<IModelColumnUnbound>().Select(
unbound => Control.GridView.Columns[unbound.PropertyName] as XafGridColumn).Where(column => column != null);
return xafGridColumns;
}
public override void SynchronizeModel() {
var xafGridColumns = GetXafGridColumns();
foreach (var xafGridColumn in xafGridColumns) {
((IModelColumnUnbound) xafGridColumn.Model).UnboundExpression = xafGridColumn.UnboundExpression;
}
}
}
The above code uses the GetXafGridColumns method to return the grid columns that correspond to IModelColumnUnbound nodes. The web implementation is very similar and can be found here.
All that is left is to register our UnboundColumnSynchronizer like this,
public class UnboundColumnController : ViewController<ListView> {
protected override void OnActivated() {
base.OnActivated();
var gridListEditor = View.Editor as GridListEditor;
if (gridListEditor != null)
gridListEditor.CreateCustomModelSynchronizer += GridListEditorOnCreateCustomModelSynchronizer;
}
void GridListEditorOnCreateCustomModelSynchronizer(object sender, CreateCustomModelSynchronizerEventArgs createCustomModelSynchronizerEventArgs) {
createCustomModelSynchronizerEventArgs.ModelSynchronizer = new UnboundColumnSynchronizer((GridListEditor)sender, View.Model);
}
}
Note; Setting ShowUnboundExpressionMenu to true is only supported by Windows platform. There, an end user can modify the UnBoundExpression by invoking Grid’s expression editor
Together with the unbound column Xpand allows for up to 5 different approaches to creating calculated fields. In the next post we will discuss the pros and cons of each approach so stay tuned!

