Skip to main content

Display a Tree List using the ITreeNode Interface

  • 8 minutes to read

To display data in a tree-like structure, the ITreeNode interface should be implemented in the appropriate business classes. The objects that support this interface are displayed via the ASPxTreeList and TreeList controls from the ASPxTreeList and XtraTreeList libraries. This is provided by the TreeList Editors module. To learn more about the ITreeNode interface and the List Editor supplied for it with the TreeList Editors module, refer to the TreeList Editors Module Overview topic. This topic demonstrates how to implement the ITreeNode interface.

Tip

A complete sample project is available in the DevExpress Code Examples database at https://supportcenter.devexpress.com/ticket/details/e1125/xaf-winforms-how-to-use-tree-list-editors-to-display-list-views.

Until the TreeList Editors Module supports ASP.NET Core Blazor UI, it is possible to implement this functionality manually. The following example demonstrates how to integrate the DevExtreme TreeList widget into your ASP.NET Core Blazor application: XAF Blazor - How to Implement a TreeList Editor.

We will implement a tree structure like this:

CategoryTreeList

CategoryTreeList Legend

For this purpose, we will implement the ProjectGroup, Project and ProjectArea classes. All of them will be inherited from an abstract class that will implement the ITreeNode interface. To display a tree of these objects, an item that corresponds to that abstract class will be added to the navigation control. When clicking this item, all the objects of the types derived from the abstract class will be organized in a tree via the TreeListEditor. This editor will be provided by the TreeList Editors module, which we will add to the application.

  • Implement an abstract Category class as shown in the following code:

    using DevExpress.Persistent.Base;
    using DevExpress.Persistent.Base.General;
    using DevExpress.Persistent.BaseImpl.EF;
    using System.ComponentModel;
    
    
    [NavigationItem]
    // Suppress XAF0002 code diagnostic
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Design",
    "XAF0002:XPO business class properties should not be overriden",
    Justification = "<Pending>")]
    public abstract class Category : BaseObject, ITreeNode {
        protected abstract ITreeNode Parent {
            get;
        }
        protected abstract IBindingList Children {
            get;
        }
        public virtual string Name { get; set; }
        #region ITreeNode
        IBindingList ITreeNode.Children {
            get {
                return Children;
            }
        }
        string ITreeNode.Name {
            get {
                return Name;
            }
        }
        ITreeNode ITreeNode.Parent {
            get {
                return Parent;
            }
        }
        #endregion
    }
    
        // Make sure that you use options.UseChangeTrackingProxies() in your DbContext settings.
    

    The NavigationItemAttribute is applied so that the corresponding navigation item is added to the navigation control.

    The Parent and Children properties will be overridden in the descendant classes, to return objects of the required types.

  • Implement the ProjectGroup, Project and ProjectArea classes by inheriting them from the Category class. The following code demonstrates how to do this:

    using DevExpress.Persistent.Base;
    using DevExpress.Persistent.Base.General;
    using System.Collections.ObjectModel;
    using System.ComponentModel;
    
    [DefaultClassOptions]
    public class ProjectGroup : Category {
        public ProjectGroup() {
            projects.CollectionChanged += (s, e) => children?.ResetBindings();
        }
        ObservableCollection<Project> projects = new ObservableCollection<Project>();
        protected override ITreeNode Parent {
            get {
                return null;
            }
        }
        protected override IBindingList Children {
            get {
                if(children == null) {
                    children = new BindingList<Project>(Projects);
                }
                return children;
            }
        }
        BindingList<Project> children;
        [DevExpress.ExpressApp.DC.Aggregated]
        public virtual ObservableCollection<Project> Projects { get => projects; }
    }
    
    public class Project : Category {
        public Project() {
            projectAreas.CollectionChanged += (s, e) => children?.ResetBindings();
        }
        protected override ITreeNode Parent { get => ProjectGroup; }
        protected override IBindingList Children {
            get {
                if(children == null) {
                    children = new BindingList<ProjectArea>(ProjectAreas);
                }
                return children;
            }
        }
        [DevExpress.ExpressApp.DC.Aggregated]
        public virtual ObservableCollection<ProjectArea> ProjectAreas { get => projectAreas; }
        ObservableCollection<ProjectArea> projectAreas = new ObservableCollection<ProjectArea>();
        BindingList<ProjectArea> children;
        public virtual ProjectGroup ProjectGroup { get; set; }
    }
    
    public class ProjectArea : Category {
        protected override ITreeNode Parent {
            get {
                return Project;
            }
        }
        BindingList<object> emptyChildren = new BindingList<object>();
        protected override IBindingList Children {
            get {
                return emptyChildren;
            }
        }
        public virtual Project Project { get; set; }
    }
    
    
    
    
        // Make sure that you use options.UseChangeTrackingProxies() in your DbContext settings.
    

    If you are using EF Core, add all created classes to your application’s DbContext.

    Note

    There are two important requirements the business classes must satisfy:

    • The parent and child classes that correspond to tree list nodes should inherit the same persistent class that implements the ITreeNode interface. In the code above, the ProjectGroup, Project and ProjectArea classes are inherited from the Category class.
    • It is not possible to have more than one root class in a tree list. In the code above, the ProjectGroup is the root class.
  • Add the TreeList Editors module as described in the following topic: TreeList Editors Module Overview.
  • Run the Windows Forms application. Click the Category item in the navigation control. Then, create ProjectGroup, Project and ProjectArea objects via the New Action. You will see that these objects will be displayed as a tree by the Category List View:

    TreeListEditor

Tree nodes can have associated images. These images are displayed by the Tree List Editors within the nodes. For details, refer to the Node Images in a Tree List interface.

You can also display a collection of items for each category node to the right of the tree list. For details, refer to the Categorized List topic.

If you do not need to organize the strong structure as demonstrated above, but wish to use the ready-to use HCategory class implementing the ITreeNode interface, refer to the Display a Tree List using the HCategory Class topic.