-
-
Notifications
You must be signed in to change notification settings - Fork 41
ModelMapper
The ModelMapper
allows to control all XAF components from the application model.
This is a platform agnostic
module that transforms any type to XAF model format and will extend the model with a simple call like:
public override void Setup(ApplicationModulesManager moduleManager) {
base.Setup(moduleManager);
moduleManager.Extend(new ModelMapperConfiguration(typeof(MyClass),typeof(IModelListView),typeof(AnyModelInterfaceType)) );
}
For each mapped type a container interface will be generated and used to extend the model. There are several extension methods you can use to identify the major mapped types for further usage such as extension or population.
typeToMap.ModelMapperContainerTypes();
typeToMap.ModelTypeName();
typeToMap.ModelMapContainerName();
typeToMap.ModelListType();
typeToMap.ModelListItemType();
//GetRepositoryItemNode, AddRepositoryItemNode, GetControlsItemNode, AddControlsItemNode
var listView = (IModelListView)application.Model.Views["Customer_ListView"];
var listViewColumn = listView.Columns["Name"];
listViewColumn.GetRepositoryItemNode(PredefinedMap.RepositoryItemButtonEdit);
listViewColumn.AddRepositoryItemNode(PredefinedMap.RepositoryItem);
var detailView = (IModelDetailView)application.Model.Views["Customer_DetailView"];
var modelPropertyEditor = detailView.Items["Name"];
modelPropertyEditor.GetRepositoryItemNode(PredefinedMap.RepositoryItemButtonEdit);
modelPropertyEditor.AddRepositoryItemNode(PredefinedMap.RepositoryItem);
To extend an existing map you can use:
public override void Setup(ApplicationModulesManager moduleManager) {
base.Setup(moduleManager);
applicationModulesManager.ExtendMap(typeof(MyClass)).Subscribe(_ => _.extenders.Add(_.targetInterface,typeof(IModelSomthing)))
}
Model Editor control on all major components used from XAF
Traditionally:
You need to create model interfaces and extend the model for all component structures. You need to link them with the actual runtime objects and editors and update their values. As this is not a non-trivial case a large number of Unit and EasyTest must run on evert build.
Xpand.XAF.Modules Solution:
The cross platform Xpand.XAF.Modules.ModelMapper ships with predefined maps
for all
the common XAF components
such as Grids, Charts, Tree, Pivot etc.
In the next screencast we see how to extend
the XAF model with the GridView
and the GridColumn
components. Then we used the model editor to modify the model and run the application to test our changes at runtime.
Generating maps for many types is costly however it happens in parallel and only once. Afterwards the model interfaces are loaded from the ModelMapperAssembly.dll
found in path. All mapped types are included in this one assembly even if the map was executed from different modules.
The module will generate automatically the ModelMapperAssembly.dll
under the following conditions.
- If the assembly does not exist in path.
- If the ModelMapper module ModuleVersionId changed.
- If any of the mapped types assembly ModuleVersionId changed.
- If Mapping customization changed. (Read more on How to customize a Map)
It is possible for the map to be outdated if an indirect reference of the participating types has changed. The solution is to simply delete the ModelMapperAssembly.dll from path and let it regenerate.
- All Public or Public Nested Types.
- All public read/write value types and string properties will be transformed to NullAble types.
- All public readOnly or read/write Reference properties.
- All public collections that their type can be detected. (They will not get populated though, it is up to the map author to customize the map as in how to customize the map section).
- All public type attributes if all their arguments Type are public.
- All Description attributes public or not, resulting in populating the ModelEditor help panel as in the next shot.
- Private or internal Types.
- Attributes where any of their argument type is not public.
- Properties marked as Obsolete or Browsable false or DesignerSerializationVisibility hidden.
- Properties that lead to recursion when a new XAF model node is generated (XAF will follow all possible paths and this can recourse).
- DevExpress DesignTime classes.
- ReservedPropertyNames, ReservedPropertyTypes, ReservedPropertyInstances (see how to customize a map).
- Already mapped types.
- The DefaultValue attribute.
- Attributes where any of their arguments is a Flag combination (XAF fails to generate such configurations).
The module ships with a large list of maps well tested, ready to use and already integrated with eXpandFramework main modules.
You are free to install any combination of them like the next snippet which installs the GridView and LayoutView maps:
public override void Setup(ApplicationModulesManager moduleManager){
base.Setup(moduleManager);
moduleManager.Extend(PredefinedMap.AdvBandedGridView,PredefinedMap.BandedGridColumn,PredefinedMap.GridView,PredefinedMap.GridColumn);
}
The predefined maps are categorized as:
-
Several
ListEditor maps
extend the IModelListView, IModelColumn and their visibility is bound to the respective ListEditor.Editor ListView Column GridListEditor AdvBandedGridListEditor LayoutViewListEditor TreeListEditor Navigation
ChartListEditor PivotGridListEditor SchedulerListEditors(Win/Web) -
The
RepositoryItems
map extend only in windows both the IModelColumn and the IModelPropertyEditor interfaces. However since the actual repository is known only in runtime, the extension is of a model list type where multiple map nodes can be added and they will be matched automatically at runtime favoring the node index.In this category the following maps exist: RepositoryItem, RepositoryItemTextEdit, RepositoryItemButtonEdit, RepositoryItemComboBox, RepositoryItemDateEdit, RepositoryFieldPicker, RepositoryItemPopupExpressionEdit, RepositoryItemPopupCriteriaEdit, RepositoryItemImageComboBox, RepositoryItemBaseSpinEdit, RepositoryItemSpinEdit, RepositoryItemObjectEdit, RepositoryItemMemoEdit, RepositoryItemLookupEdit, RepositoryItemProtectedContentTextEdit, RepositoryItemBlobBaseEdit, RepositoryItemRtfEditEx, RepositoryItemHyperLinkEdit, RepositoryItemPictureEdit, RepositoryItemCalcEdit, RepositoryItemCheckedComboBoxEdit, RepositoryItemColorEdit, RepositoryItemFontEdit, RepositoryItemLookUpEditBase, RepositoryItemMemoExEdit, RepositoryItemMRUEdit, RepositoryItemBaseProgressBar, RepositoryItemMarqueeProgressBar, RepositoryItemProgressBar, RepositoryItemRadioGroup, RepositoryItemTrackBar, RepositoryItemRangeTrackBar, RepositoryItemTimeEdit, RepositoryItemZoomTrackBar, RepositoryItemImageEdit, RepositoryItemPopupContainerEdit, RepositoryItemPopupBase, RepositoryItemPopupBaseAutoSearchEdit--- --- -
The
Controls
maps extends in both platforms the IModelPropertyEditor interface in a design similar to the RepositoryItem maps.
In this category we find the following maps: RichEditControl, DashboardViewer, ASPxDashboard, ASPxHtmlEditor, ASPxUploadControl, ASPxDateEdit, ASPxHyperLink, ASPxLookupDropDownEdit, ASPxLookupFindEdit, ASPxSpinEdit, ASPxTokenBox, ASPxComboBoxWindows Web -
Module specific maps
. In this category we have the DashboardDesigner map which extends the IModelDashboardModule interface as shown:
-
In the
IModelView related maps
category we find the XafLayoutControl, the SplitContainerControl and the PopupControl maps.
XafLayoutControl | SplitContainerControl |
---|---|
![]() |
![]() |
ASPxPopupControl
DashboardView | ListView | DetailView |
---|---|---|
![]() |
![]() |
![]() |
You can customize the map the following ways:
- On declaration using the ModelMapperConfiguration properties.
public interface IModelMapperConfiguration{ string VisibilityCriteria{ get; } string ContainerName{ get; } string MapName{ get; } string DisplayName{ get; } string ImageName{ get; } List<Type> TargetInterfaceTypes { get; } Type TypeToMap{ get; set; } bool OmitContainer{ get; } }
- Using static collections of the
TypeMappingService
class such as ReservedPropertyNames, ReservedPropertyTypes, ReservedPropertyInstances, AdditionalTypesList, AdditionalReferences - Adding or inserting Type or Property related rules. For example to disable the map of all attributes you can write:
TypeMappingService.PropertyMappingRules.Add(("Disable", tuple => { foreach (var modelMapperPropertyInfo in tuple.propertyInfos){ foreach (var modelMapperCustomAttributeData in modelMapperPropertyInfo.GetCustomAttributesData().ToArray()){ modelMapperPropertyInfo.RemoveAttributeData(modelMapperCustomAttributeData); } } }));
Several real world examples are available at Predefined namespace.
All predefined maps are bound to the runtime instance automatically. The module when any view controls are created will search its model for IModelModelMap properties and use them to configure the related instances. It is possible to customize the process as in next snippet:
ModelBindingService.ControlBind.Subscribe(parameter => parameter.Handled = true);
If you create a custom map you can manually map as:
modelNode.BindTo(objectInstance)
The BindTo
method will follow the hierarchy tree respecting the disabled nodes and will update all properties that are not null.
- Chart Calculated fields #717.
- Any other need you may have.
-
First you need the nuget package so issue this command to the
VS Nuget package console
Install-Package Xpand.XAF.Modules.ModelMapper
.The above only references the dependencies and nexts steps are mandatory.
-
Ways to Register a Module or simply add the next call to your module constructor
RequiredModuleTypes.Add(typeof(Xpand.XAF.Modules.ModelMapperModule));
The module is not bound to DevExpress versioning, which means you can use the latest version with your old DevExpress projects Read more.
The module follows the Nuget Version Basics.
.NetFramework: net461
DevExpress.ExpressApp | Any |
Enums.NET | 3.0.3 |
Fasterflect.Xpand | 2.0.7 |
JetBrains.Annotations | 2020.1.0 |
Mono.Cecil | 0.11.2 |
System.CodeDom | 4.7.0 |
System.Interactive | 4.1.1 |
System.Reactive | 4.4.1 |
System.ValueTuple | 4.5.0 |
Xpand.Collections | 1.0.1 |
Xpand.Extensions | 2.202.57 |
Xpand.Extensions.Reactive | 2.202.58 |
Xpand.Extensions.XAF | 2.202.58 |
Xpand.XAF.Modules.Reactive | 2.202.58 |
Xpand.VersionConverter | 2.202.10 |
To Step in the source code
you need to enable Source Server support
in your Visual Studio/Tools/Options/Debugging/Enable Source Server Support. See also How to boost your DevExpress Debugging Experience.
If the package is installed in a way that you do not have access to uninstall it, then you can unload
it with the next call at the constructor of your module.
Xpand.XAF.Modules.Reactive.ReactiveModuleBase.Unload(typeof(Xpand.XAF.Modules.ModelMapper.ModelMapperModule))
The module is tested on Azure for each build with these tests