In this post I want to let you know about a number of exciting improvements to the Application Model and to the Model Editor that will be available in V2010 Vol1. Firstly, we have greatly optimised the model generation. In fact generation now happens around 100 times faster than in previous versions! So what does that mean for your users? Well it means that the average XAF application now launches around 60% faster than before! But we’re not finished there, application startup time also consists of the time spent collecting information on the types used in the application and we have targeted this area for improvement in the 10.2 release timeframe. If you want to keep up to date with our progress in this particular area, you can track this suggestion.
The next improvement I want to tell you about is to the Model Editor. If you’ve been using XAF in a non trivial way, you may have noticed that if you open the Model Editor you can be visually swamped by the attributes – wouldn’t it be really cool if you could group those attributes by category? Well, good news, now you can! As of 10.1 you’ll be able to decorate your interface attributes with CategoryAttribute and that will cause the Model Editor to group those attributes by the specified category. All the standard XAF application model attributes belong to one of the common categories described here. If an attribute is not decorated with CategortyAttribute then it will appear in the Misc. category by default. An example of this is shown below:

Another improvement to the Model Editor is that it is now possible to select members of complex properties in a drop-down editor, containing a tree structure of your business model as shown below:
Another improvement is that identifiers for the most nodes are now generated automatically. If you extend the application model and follow the naming convention for node identifiers, then their values will be generated automatically. We recommend that you declare the 'Id' property (the last character is in lower case). This property will always be recognized as the key even if the KeyPropertyAttribute doesn't point to it. Although this is a small feature, it will save time when customizing the application model and also overcome some previous limitation, like the one mentioned here.
The last improvement I’m going to talk about in this post is the fact that it is now possible to use the DC technology to easily inject additional business logic into the application model. Let’s consider a couple of examples:
Example 1
Before:
<Element Name=""EditorStateRule="""" …="" >
…
<Attribute Name=""TypeInfo="""" RefNodeName=""/Application/BOModel/Class"" Required=""True"" />
…
Now:
public interface IModelEditorStateRule : IModelNode, IEditorStateRule {
…
[ModelPersistentName("TypeInfo")]
[DataSourceProperty("Application.BOModel"), Required]
IModelClass ModelClass { get; set; }
…
}
Note that XAF’s DataSourcePropertyAttribute is used in the same manner as when you want to provide a data source for a lookup property in your business class. Since our interface is derived from the IModelNode one we can access its Application property and its nested properties. Also note that for the backward compatibility (for example, not to lose old model differences) the ModelPersistentNameAttribute is used to map the new property to the old name.
Example 2
Before:
<Element Name=""NavigationItems="""" …="" >
...
<Attribute Name=""Current="""" RefNodeName=""{DevExpress.ExpressApp.Core.DictionaryHelpers.CurrentNavigationItemNodeProvider=""}""/>
...
</Element>
Now:
public interface IModelNavigationItems : IModelNode, IModelList<IModelNavigationItem> {
...
[Browsable(false)]
IModelList<IModelNavigationItem> AllItems { get; }
[ModelPersistentName("Current")]
[DataSourceProperty("AllItems")]
IModelNavigationItem StartupNavigationItem { get; set; }
...
[DomainLogic(typeof(IModelNavigationItems))]
public static class ModelNavigationItemsDomainLogic {
...
public static IModelList<IModelNavigationItem> Get_AllItems(IModelNavigationItems navigationItems) {
CalculatedModelNodeList<IModelNavigationItem> result = new CalculatedModelNodeList<IModelNavigationItem>();
foreach(IModelNavigationItem navigationItem in navigationItems) {
result.Add(navigationItem);
result.AddRange(GetChildItems(navigationItem));
}
return result;
}
...
}
…
Here we have introduced a hidden ([Browsable(false)]) service property (AllItems) and set it as a data source for our StartupNavigationItem attribute. It’s exactly the same as the popular Scenario 4 in the help topic about filtering lookups.
Example 3
Before:
<Element Name="Class" ...="" >
...
<Attribute Name="GroupName" IsReadOnly="True"/>
<Attribute Name="IsNavigationItem" IsReadOnly="true" Choice="True,False" />
...
Now:
public interface IModelClassNavigation {
[ReadOnly(true)]
bool IsNavigationItem { get; set; }
[ReadOnly(true)]
string GroupName { get; set; }
}
[DomainLogic(typeof(IModelClassNavigation))]
public static class ModelClassNavigationItemDomainLogic {
public static bool Get_IsNavigationItem(IModelClass modelClass) {
...
}
public static string Get_GroupName(IModelClass modelClass) {
...
}
...
}
Here we added a domain logic to calculate default values for read-only attributes shown for the class node in the BOModel.
Example 4
Before:
<Element Name="Filters" Multiple="False">
…
<Attribute Name="CurrentFilterID"
RefNodeName="{DevExpress.ExpressApp.Core.DictionaryHelpers.ChildrenRefNodeProvider}" />
…
Now:
public interface IModelListViewFilters : IModelNode, IModelList<IModelListViewFilterItem>
{
[ModelPersistentName("CurrentFilterId")]
[DataSourceProperty("this")]
IModelListViewFilterItem CurrentFilter { get; set; }
}
Okay, that’s enough examples for today, I don’t want your heads to start spinning :-)
If you want to see more examples, you can check out the sources and the docs (once they are available <grin>). They’ll describe the most common cases, in which domain logic can be effectively used to extend the application model.
The bottom line is that things become easier with the improvements to XAF. For example, in previous versions to achieve the same tasks you had to use complicated approaches that quite often utilized undocumented schema attributes and internal classes from the DevExpress.ExpressApp.Core.DictionaryHelpers namespace. This, of course, made life difficult for inexperienced users, not to mention the fact that we don’t recommend that developers use undocumented classes :-)
Now the same, well-understood technology, used to implement business logic in your classes, can be used in the application model and Model Editor, which means you can now use the same techniques and approaches that you are familiar with.
Well that’s all for this post, until next time, happy XAFing! :-)