expressappframework-405312-app-shell-and-base-infrastructure-tree-list-editors-display-a-tree-list-with-flat-data-objects-asp-net-core-blazor.md
ASP.NET Core Blazor DxTreeListEditor component can display a flat data object collection as a tree-like structure. To make this possible, objects in the data source should have relationships defined by Key and Parent Key properties. This topic shows an example of such implementation.
Note
In this scenario, classes do not need to implement the ITreeNode interface.
First, implement a simple class with a ParentObjectId property that targets a parent node’s key value.
HasChildren property allows you to use Queryable data access mode. In this mode, Tree List loads child nodes from the database only when you expand the parent node. The HasChildren property shows whether the parent object should contain children.
Note
If you make this property persistent, XAF initially queries only visible nodes from the database.
If this property is calculated, XAF loads the next level to allow the Tree List to evaluate whether nodes have children.
using DevExpress.Persistent.Base;
using DevExpress.Persistent.BaseImpl.EF;
using System.Collections.ObjectModel;
namespace SolutionName.Module.BusinessObjects;
[DefaultClassOptions]
public class Category : BaseObject {
public virtual string Name { get; set; }
[HideInUI(HideInUI.ListViewColumn | HideInUI.DetailViewEditor)]
public virtual Guid ParentObjectId { get; set; }
// Add this property if you use Queryable data access mode.
[HideInUI(HideInUI.ListViewColumn | HideInUI.DetailViewEditor)]
[PersistentAlias("[<MyApplication.Module.BusinessObjects.Category>][ParentObjectId = ^.ID and ID != ^.ID]")]
public bool HasChildren => EvaluateAlias<bool>();
}
using DevExpress.Persistent.Base;
using DevExpress.Persistent.BaseImpl;
using DevExpress.Xpo;
namespace SolutionName.Module.BusinessObjects;
[DefaultClassOptions]
public class Category : BaseObject {
public Category(Session session) : base(session) { }
private string name;
public string Name {
get => name;
set => SetPropertyValue(nameof(Name), ref name, value);
}
private Guid parentObjectId;
[HideInUI(HideInUI.ListViewColumn | HideInUI.DetailViewEditor)]
public Guid ParentObjectId {
get => parentObjectId;
set => SetPropertyValue(nameof(ParentObjectId), ref parentObjectId, value);
}
// Add this property if you use Queryable data access mode.
[HideInUI(HideInUI.ListViewColumn | HideInUI.DetailViewEditor)]
[PersistentAlias("[<SolutionName.Module.BusinessObjects.Category>][ParentObjectId = ^.Oid and Oid != ^.Oid]")]
public bool HasChildren => Convert.ToBoolean(EvaluateAlias("HasChildren"));
}
You can make the HasChildren property persistent (stored in the database):
Add a getter and setter
Remove the PersistentAlias attribute
//...
[HideInUI(HideInUI.ListViewColumn | HideInUI.DetailViewEditor)]
public virtual bool HasChildren { get; set; }
//...
private bool hasChildren;
[HideInUI(HideInUI.ListViewColumn | HideInUI.DetailViewEditor)]
public bool HasChildren {
get {
return hasChildren;
}
set {
SetPropertyValue(nameof(HasChildren), ref hasChildren, value);
}
}
If your application uses EF Core Framework, register the Category class in the DBContext.
File: SolutionName.Module\BusinessObjects\SolutionNameDbContext.cs
using DevExpress.ExpressApp.EFCore.Updating;
using DevExpress.Persistent.BaseImpl.EF;
using Microsoft.EntityFrameworkCore;
namespace SolutionName.Module.BusinessObjects;
// ...
public class SolutionNameDbContext : DbContext {
// ...
public SolutionNameDbContext(DbContextOptions<SolutionNameDbContext> options)
: base(options) {
}
// ...
public DbSet<Category> Categories { get; set; }
}
In your ASP.NET Core Blazor project (SolutionName.Blazor.Server), open Model Editor and navigate to the Category_ListView node.
In the EditorType property, specify the DevExpress.ExpressApp.Blazor.Editors.DxTreeListEditor value.
Specify the KeyFieldName, ParentKeyFieldName, and HasChildrenFieldName properties as follows:
Run the ASP.NET Core Blazor application and click the Category item in the navigation control.
To create a top-level Category object, use the New Action.
To create a child object, select the parent object in the tree list and click the New action.
Add the ParentObject and Children properties to the Category class. Make ParentObjectId nullable to use it as a foreign key.
To configure the One-to-Many relationship between objects of the Category type, use the OnModelCreating method of your DbContext descendant.
In your ASP.NET Core Blazor project (SolutionName.Blazor.Server), open Model Editor and navigate to the Category_Children_ListView node.
In the EditorType property, specify the DevExpress.ExpressApp.Blazor.Editors.DxTreeListEditor value.
Specify the KeyFieldName, ParentKeyFieldName, and HasChildrenFieldName properties as follows:
Add the ParentObject and Children properties to the Category class.
To configure the One-to-Many relationship between objects of the Category type, use the Association attribute.
Handle the CollectionChanged event of the Children collection to update the HasChildren property when child objects are removed.
Create a controller to handle the assignment of the ParentObject property when new child objects are created or existing child objects are orphaned.
In your ASP.NET Core Blazor project (SolutionName.Blazor.Server), open Model Editor and navigate to the Category_Children_ListView node.
In the EditorType property, specify the DevExpress.ExpressApp.Blazor.Editors.DxTreeListEditor value.
Specify the KeyFieldName, ParentKeyFieldName, and HasChildrenFieldName properties as follows: