Display a Tree List using the ITreeNode Interface
- 7 minutes to read
To display data in a tree-like structure, implement the ITreeNode interface in the corresponding business classes. XAF uses the DxTreeList
, ASPxTreeList
, and TreeList
controls provided by the TreeList Editors module and DevExpress.ExpressApp.Blazor base module to display objects that support ITreeNode.
For more information about the ITreeNode
interface, refer to the following topic: TreeList Editors Module Overview.
This topic demonstrates the implementation of the ITreeNode
interface.
Tip
A complete sample project is available in the DevExpress Code Examples database at https://supportcenter.
Dx
ships with the base DevExpress.
module. You do not need to add a module to an existing XAF ASP.
Follow instructions in this example to implement the following tree structure:
You need the following classes:
- ProjectGroup
- Project
- ProjectArea
Derive these classes from an abstract class that implements the ITreeNode
interface. To display a tree of these objects, add an item that corresponds to that abstract class to the navigation control. When you click this item, XAF organizes all objects of the types derived from the abstract class in a tree via the Tree List editors (you need to add the TreeList Editors module to the application).
Note
Business classes you implement in this example must meet the following requirements:
- The parent and child classes corresponding to tree list nodes should be derived from the same persistent class that implements the
ITree
interface. In this example, theNode Project
,Group Project
, andProject
classes are derived from theArea Category
class. - It is impossible to have more than one root class in a Tree List. In this example, the
Project
is the root class.Group
Implement an abstract
Category
class as the following code snippet demonstrates:using DevExpress.Persistent.Base; using DevExpress.Persistent.Base.General; using DevExpress.Persistent.BaseImpl.EF; using System.ComponentModel; namespace MySolution.Module.BusinessObjects; [NavigationItem("Category")] 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.
Apply the NavigationItemAttribute to add the corresponding navigation item to the navigation control. This overrides the
Parent
andChildren
properties in the descendant classes to return objects of the required types.Implement the
ProjectGroup
,Project
, andProjectArea
classes. Derive these classes from theCategory
class.Entity Framework Core classes:
using DevExpress.Persistent.Base; using DevExpress.Persistent.Base.General; using System.Collections.ObjectModel; using System.ComponentModel; namespace MySolution.Module.BusinessObjects; [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; } } // Make sure that you use options.UseChangeTrackingProxies() in your DbContext settings.
XPO classes:
using DevExpress.Persistent.Base.General; using DevExpress.Xpo; using System.ComponentModel; namespace MySolution.Module.BusinessObjects; [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "XAF0002:XPO business class properties should not be overriden", Justification = "")] public class ProjectGroup : Category { protected override ITreeNode Parent { get { return null; } } protected override IBindingList Children { get { return Projects; } } public ProjectGroup(Session session) : base(session) { } public ProjectGroup(Session session, string name) : base(session) { this.Name = name; } [Association("ProjectGroup-Projects"), Aggregated] public XPCollection<Project> Projects { get { return GetCollection<Project>(nameof(Projects)); } } }
Tip
If your application uses Entity Framework Core, register new classes in your application’s DBContext:
C#using MySolution.Module.BusinessObjects; namespace MySolution.Module.BusinessObjects; public class MySolutionEFCoreDbContext : DbContext { //... public DbSet<Category> Categories { get; set; } public DbSet<Project> Projects { get; set; } public DbSet<ProjectArea> ProjectAreas { get; set; } public DbSet<ProjectGroup> ProjectGroups { get; set; } }
In a Windows Forms or an ASP.NET Web Forms project, add the TreeList Editors module as described in the following topic: TreeList Editors Module Overview.
- Run the application. Click the
Category
item in the navigation control and use the New Action to createProjectGroup
,Project
, andProjectArea
objects. TheCategory
List View displays these objects as a hierarchical tree:
- ASP.NET Core Blazor
- Windows Forms
Note
In Windows Forms applications, Tree List nodes can have associated images. Tree List Editors display these images within the nodes. For more information, refer to the following topic: Node Images in a Tree List. In Windows Forms applications, you can also display a collection of items for each category node to the right of the Tree List. For more information, refer to the following topic: Categorized List (Windows Forms).
If you do not require the hard-coded structure as demonstrated in this example, use the HCategory
class that implements the ITreeNode
interface out of the box. For more information, refer to the following topic: Display a Tree List using the HCategory Class.