How to: Create Additional ListView Nodes in Code using a Generator Updater

By default, two ListView nodes are generated in the Application Model for each business class. These nodes represent a general-purpose List View, and a Lookup List View that contains fewer columns (see List View Column Generation). Often, it is required to add more List Views manually. These additional List Views can be used as View Variants, Dashboard items, etc. Typically, this task can be accomplished in the Model Editor. However, in certain scenarios, adding nodes in code may be required. The default process of generating Views node's child nodes is handled by the built-in ModelViewsNodesGenerator Nodes Generator. To customize this process, you should "attach" a Generator Updater class to this Generator. This topic describes how to implement a Generator Updater that creates custom ListView nodes. Additionally, an Updater that creates View Variants using these new nodes is illustrated. For details on Nodes Generators and Generator Updaters, refer to the Extend and Customize the Application Model in Code topic.

Note

Mobile applications do not support the View Variant, so the approach described in this topic is not supported by the Mobile platform.

Create List Views

Let us consider the following Employee business class.

[DefaultClassOptions, ImageName("BO_Person")]
public class Employee : BaseObject {
    public Employee(Session session) : base(session) { }
    private string firstName;
    private string lastName;
    private string position;
    private string email;
    public string FirstName {
        get { return firstName; }
        set { SetPropertyValue("FirstName", ref firstName, value); }
    }
    public string LastName {
        get { return lastName; }
        set { SetPropertyValue("LastName", ref lastName, value); }
    }
    public string FullName {
        get { return String.Format("{0} {1}", FirstName, LastName); }
    }
    public string Position {
        get { return position; }
        set { SetPropertyValue("Position", ref position, value); }
    }
    public string Email {
        get { return email; }
        set { SetPropertyValue("Email", ref email, value); }
    }
}

The List View generated by default for this class is illustrated below.

GeneratorUpdater_DefaultListView

This List View is defined by the Views | Employee_ListView node. Let us implement a Generator Updater that generates two additional List Views, which are:

  1. A List View with hidden FirstName and LastName columns (Employee_ListView_FewColumns);
  2. A List View where records are grouped by the Position column (Employee_ListView_Grouped).

A Generator Updater class should inherit the abstract ModelNodesGeneratorUpdater<T> class, where T is the type of the Nodes Generator to be customized. A built-in Nodes Generator that generates the Views node content is the ModelViewsNodesGenerator. The abstract ModelNodesGeneratorUpdater`1.UpdateNode method must be implemented in a custom Generator Updater. The parameter of the ModelNode type, passed to this method, represents a generated node. In our case, this node is the Views node. To add child nodes, the ModelNode.AddNode<T> method can be used. Note that the IModelObjectView.ModelClass property must be specified for each ListView node. After that, the ListView node properties can be accessed and their values can be customized. To access the Columns node, use the IModelListView.Columns property. The following snippet illustrates the AddListViewNodesGeneratorUpdater Generator Updater class.

using DevExpress.ExpressApp.Model;
using DevExpress.ExpressApp.Model.Core;
using DevExpress.ExpressApp.Model.NodeGenerators;
// ...
public class AddListViewNodesGeneratorUpdater : 
    ModelNodesGeneratorUpdater<ModelViewsNodesGenerator> {
    public const string FewColumnsListViewNodeIdSuffix = "_FewColumns";
    string[] columnsToHideIds = { "FirstName", "LastName" };
    public const string GroupedListViewNodeIdSuffix = "_Grouped";
    public const string GroupByColumnId = "Position";
    static Type targetType = typeof(Employee);
    public override void UpdateNode(ModelNode viewsNode) {
        AddFewColumnsListViewNode(viewsNode);
        AddGroupedListViewNode(viewsNode);
    }
    public static IModelListView GetDefaultListView(ModelNode viewsNode) {
        return viewsNode.Application.BOModel.GetClass(targetType).DefaultListView;
    }
    IModelListView AddListViewNode(ModelNode viewsNode, string listViewId) {
        IModelListView listViewNode = (IModelListView)viewsNode.AddNode<IModelListView>(listViewId);
        listViewNode.ModelClass = viewsNode.Application.BOModel.GetClass(targetType);
        return listViewNode;
    }
    void AddFewColumnsListViewNode(ModelNode viewsNode) {
        string nodeId = GetDefaultListView(viewsNode).Id + FewColumnsListViewNodeIdSuffix;
        IModelListView fewColumnsListViewNode = AddListViewNode(viewsNode, nodeId);
        IModelColumns columns = (IModelColumns)fewColumnsListViewNode.Columns;
        foreach (string columnId in columnsToHideIds) {
            columns[columnId].Index = -1;
        }
    }
    void AddGroupedListViewNode(ModelNode viewsNode) {
        string nodeId = GetDefaultListView(viewsNode).Id + GroupedListViewNodeIdSuffix;
        IModelListView groupedListViewNode =
            AddListViewNode(viewsNode, nodeId);
        IModelColumns columns = (IModelColumns)groupedListViewNode.Columns;
        columns[GroupByColumnId].GroupIndex = 1;
    }
}

You can place this class in a separate code file in the module project, or add it to the Module.cs (Module.vb) file. The implemented Generator Updater should be registered in the overridden ModuleBase.AddGeneratorUpdaters method in the following manner:

using DevExpress.ExpressApp.Model.Core;
// ...
public sealed partial class CreateNodesInCodeModule : ModuleBase {
    // ...
    public override void AddGeneratorUpdaters(ModelNodesGeneratorUpdaters updaters) {
        base.AddGeneratorUpdaters(updaters);
        updaters.Add(new AddListViewNodesGeneratorUpdater());
    }
}

After implementing and registering the Generator Updater, rebuild the solution and invoke the Model Editor. The new ListView nodes are illustrated below.

GeneratorUpdater_ModelEditor_NewNodes

Note

Your custom nodes and properties are not marked in bold font in the Model Editor, because these changes are generated in code. You can check the Model.DesignedDiffs.xafml source to ensure that it contains no customizations related to the generated nodes.

Create View Variants

Let us implement View Variants for Employee List View to make List Views created in the previous section of this topic visible in the UI. Although the View Variants are typically designed in the Model editor, it is also possible to create View Variants in code, via the Generator Updater. The Generator Updater that generates View Variants using Views created by the AddListViewNodesGeneratorUpdater is illustrated in the snippet below. The View Variants module should be added before implementing this class (see Provide Several View Variants for End-Users).

using DevExpress.ExpressApp.Model;
using DevExpress.ExpressApp.Model.Core;
using DevExpress.ExpressApp.Model.NodeGenerators;
using DevExpress.ExpressApp.ViewVariantsModule;
// ...
class AddViewVariantsGeneratorUpdater : ModelNodesGeneratorUpdater<ModelViewsNodesGenerator> {
    public override void UpdateNode(ModelNode viewsNode) {
        IModelView rootView = AddListViewNodesGeneratorUpdater.GetDefaultListView(viewsNode);
        IModelView fewColumnsListView = 
            (IModelView)viewsNode.GetNode(rootView.Id +
            AddListViewNodesGeneratorUpdater.FewColumnsListViewNodeIdSuffix);
        IModelView groupedListView =
            (IModelView)viewsNode.GetNode(rootView.Id +
            AddListViewNodesGeneratorUpdater.GroupedListViewNodeIdSuffix);
        AddVariant("Default", "Default", rootView, rootView, true);
        AddVariant("FewColumns", "Few Columns", rootView, fewColumnsListView, false);
        AddVariant("Grouped", "Grouped", rootView, groupedListView, false);
    }
    void AddVariant(string variantId, string caption, 
        IModelView rootView, IModelView variantView, bool isCurrent) {
        IModelVariants variants = ((IModelViewVariants)rootView).Variants;
        IModelVariant variant = variants.AddNode<IModelVariant>(variantId);
        variant.View = variantView;
        variant.Caption = caption;
        if (isCurrent) variants.Current = variant;
    }
}

This Generator Updater should also be registered in the module's AddGeneratorUpdaters method.

public sealed partial class CreateNodesInCodeModule : ModuleBase {
    // ...
    public override void AddGeneratorUpdaters(ModelNodesGeneratorUpdaters updaters) {
        base.AddGeneratorUpdaters(updaters);
        updaters.Add(new AddListViewNodesGeneratorUpdater());
        updaters.Add(new AddViewVariantsGeneratorUpdater());
    }
}

After implementing and registering the Generator Updater, rebuild the solution and invoke the Model Editor for the module project. The new Variant nodes are illustrated below.

GeneratorUpdater_ModelEditor_NewVariants

Now you can test the implemented Views and View Variants at runtime.

  • Windows Forms Application:

    GeneratorUpdater_WinApp

  • ASP.NET Application:

    GeneratorUpdater_WebApp

You can use a similar approach to create Generator Updaters for built-in or custom Nodes Generators.

See Also