Back to Devexpress

Virtual Mode - Binding to a Hierarchical Business Object (Data Source Level)

windowsforms-2486-controls-and-libraries-tree-list-feature-center-data-binding-virtual-mode-binding-to-a-hierarchical-business-object-data-source-level.md

latest14.7 KB
Original Source

Virtual Mode - Binding to a Hierarchical Business Object (Data Source Level)

  • Oct 29, 2020
  • 9 minutes to read

In a hierarchical data source, items are linked by “parent-child” relationships at the data source level. A typical hierarchical data source is a business object that returns child items in a collection property. A TreeList bound to a list of these business objects automatically builds a node hierarchy. See Implement Hierarchical Data Source Using Collection Property (ChildListFieldName) for details.

Your hierarchical data source may not provide this collection property or you may need greater control over the interaction between the TreeList and the data source. In these cases, you can still provide data hierarchy information to the TreeList at the data source level by implementing the IVirtualTreeListData interface. The TreeList bound to this data source only loads and saves data using this interface’s methods. See Implement Hierarchical Data Source Using IVirtualTreeListData Interface for more information.

It is also possible to provide information on a data hierarchy at the TreeList level by handling the control’s dedicated events. See Virtual Mode (Dynamic Data Loading) Using Events (Tree List Level).

Implement a Hierarchical Data Source Using Collection Property

You can create a hierarchical business object that returns children using a collection property. When a TreeList is bound to a list of these business objects, it automatically builds a node hierarchy by iterating through the specified collection property. This binding approach does not require additional interfaces at the data source level.

Set up the TreeList as follows:

  1. Create a business object and define a public collection property that returns child items.
  2. Bind a list of business objects to the TreeList’s TreeList.DataSource property.
  3. Set the TreeList.ChildListFieldName property to this collection property name.

When you run the application, the TreeList control will automatically build a node hierarchy by iterating through the business object list and specified child item collections.

Example

This example binds a TreeList to a list of Employee objects. The control creates child nodes from employees’ Subordinates collections.

csharp
using System.Collections.Generic;
using System.Windows.Forms;

namespace WindowsFormsApplication1 {
    public partial class Form1 : Form {
        public Form1() {
            InitializeComponent();
        }
        private void Form1_Load(object sender, System.EventArgs e) {
            Employee emp1 = new Employee() { JobTitle = "Chief Executive Officer", Name = "Bruce Cambell", City = "Oaks" };
            Employee emp2 = new Employee() { JobTitle = "Information Services Manager", Name = "Cindy Haneline", City = "Vista" };
            Employee emp3 = new Employee() { JobTitle = "Database Administrator", Name = "Andrea Deville", City = "Aurora" };
            Employee emp4 = new Employee() { JobTitle = "Application Specialist", Name = "Anita Ryan", City = "West" };
            Employee emp5 = new Employee() { JobTitle = "Network Manager", Name = "Anita Cardle", City = "Glendale" };
            Employee emp6 = new Employee() { JobTitle = "Network Administrator", Name = "Andrew Carter", City = "Moline" };
            Employee emp7 = new Employee() { JobTitle = "Marketing Manager", Name = "Carolyn Baker", City = "Longview" };

            emp1.Subordinates = new List<Employee>() { emp2, emp7};
            emp2.Subordinates = new List<Employee>() { emp3, emp4, emp5 };
            emp5.Subordinates = new List<Employee>() { emp6 };

            List<Employee> dataSource = new List<Employee>();
            dataSource.Add(emp1);

            treeList1.ChildListFieldName = "Subordinates";
            treeList1.DataSource = dataSource;
        }
    }

    public class Employee {
        public Employee() {
        }
        public string JobTitle { get; set; }
        public string Name { get; set; }
        public string City { get; set; }
        public IList<Employee> Subordinates { get; set; }
    }
}
vb
Partial Public Class Form1
    Public Sub New()
        InitializeComponent()
    End Sub

    Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim emp1 As Employee = New Employee() With {.JobTitle = "Chief Executive Officer", .Name = "Bruce Cambell", .City = "Oaks"}
        Dim emp2 As Employee = New Employee() With {.JobTitle = "Information Services Manager", .Name = "Cindy Haneline", .City = "Vista"}
        Dim emp3 As Employee = New Employee() With {.JobTitle = "Database Administrator", .Name = "Andrea Deville", .City = "Aurora"}
        Dim emp4 As Employee = New Employee() With {.JobTitle = "Application Specialist", .Name = "Anita Ryan", .City = "West"}
        Dim emp5 As Employee = New Employee() With {.JobTitle = "Network Manager", .Name = "Anita Cardle", .City = "Glendale"}
        Dim emp6 As Employee = New Employee() With {.JobTitle = "Network Administrator", .Name = "Andrew Carter", .City = "Moline"}
        Dim emp7 As Employee = New Employee() With {.JobTitle = "Marketing Manager", .Name = "Carolyn Baker", .City = "Longview"}
        emp1.Subordinates = New List(Of Employee)() From {emp2, emp7}
        emp2.Subordinates = New List(Of Employee)() From {emp3, emp4, emp5}
        emp5.Subordinates = New List(Of Employee)() From {emp6}
        Dim dataSource As List(Of Employee) = New List(Of Employee)()
        dataSource.Add(emp1)
        TreeList1.ChildListFieldName = "Subordinates"
        TreeList1.DataSource = dataSource
    End Sub
End Class

Public Class Employee
    Public Sub New()
    End Sub
    Public Property JobTitle As String
    Public Property Name As String
    Public Property City As String
    Public Property Subordinates As IList(Of Employee)
End Class

Demo: Registry Viewer module in the XtraTreeList MainDemo

Implement Hierarchical Data Source Using IVirtualTreeListData Interface

If a business object contains hierarchical data, you can present this hierarchy in the TreeList by implementing the DevExpress.XtraTreeList.IVirtualTreeListData interface for the business object.

Important

This approach is not applicable to the TreeListLookUpEdit control.

The TreeList will create nodes on demand based on the data the IVirtualTreeListData interface methods provide. The interface methods fire when the TreeList needs to generate root and child nodes, display node values, and when node values are modified.

  1. Create a business object that supports the DevExpress.XtraTreeList.IVirtualTreeListData interface, and handle the following two interface methods.

  2. If you need to save changes made by an end-user while editing node cells and node check states, implement the following interface method.

  3. Bind a business object instance to the TreeList.DataSource property.

You can use the TreeList.EnableDynamicLoading property to build a node hierarchy on node expansion.

Example

The following example shows how to support a tree structure for a business object ( Node class) using the IVirtualTreeListData interface. The example implements all three interface methods.

csharp
using DevExpress.XtraTreeList;
using DevExpress.XtraTreeList.Columns;
using System.Collections;
using System.Windows.Forms;

public class Node : TreeList.IVirtualTreeListData {
    protected Node parentCore;
    protected ArrayList childrenCore = new ArrayList();
    protected object[] cellsCore;

    public Node(Node parent, object[] cells) {
        this.parentCore = parent;
        this.cellsCore = cells;
        if (this.parentCore != null) {
            this.parentCore.childrenCore.Add(this);
        }
    }
    void TreeList.IVirtualTreeListData.VirtualTreeGetChildNodes(VirtualTreeGetChildNodesInfo info) {
        info.Children = childrenCore;
    }
    void TreeList.IVirtualTreeListData.VirtualTreeGetCellValue(VirtualTreeGetCellValueInfo info) {
        info.CellData = cellsCore[info.Column.AbsoluteIndex];
    }

    void TreeList.IVirtualTreeListData.VirtualTreeSetCellValue(VirtualTreeSetCellValueInfo info) {
        cellsCore[info.Column.AbsoluteIndex] = info.NewCellData;
    }
}
vb
Imports System.Collections
Imports DevExpress.Data
Imports DevExpress.XtraTreeList
Imports DevExpress.XtraTreeList.Columns

Public Class Node
    Implements TreeList.IVirtualTreeListData
    Protected parentCore As Node
    Protected childrenCore As New ArrayList()
    Protected cellsCore() As Object

    Public Sub New(ByVal parent As Node, ByVal cells() As Object)
        Me.parentCore = parent
        Me.cellsCore = cells
        If Not (Me.parentCore Is Nothing) Then
            Me.parentCore.childrenCore.Add(Me)
        End If
    End Sub

    Sub VirtualTreeGetChildNodes(ByVal info As VirtualTreeGetChildNodesInfo) _
    Implements TreeList.IVirtualTreeListData.VirtualTreeGetChildNodes
        info.Children = childrenCore
    End Sub

    Sub VirtualTreeGetCellValue(ByVal info As VirtualTreeGetCellValueInfo) _
    Implements TreeList.IVirtualTreeListData.VirtualTreeGetCellValue
        info.CellData = cellsCore(info.Column.AbsoluteIndex)
    End Sub

    Sub VirtualTreeSetCellValue(ByVal info As VirtualTreeSetCellValueInfo) _
    Implements TreeList.IVirtualTreeListData.VirtualTreeSetCellValue
        cellsCore(info.Column.AbsoluteIndex) = info.NewCellData
    End Sub

End Class

The following code creates a Node class object and binds it to TreeList.

csharp
public partial class Form1 : Form {
    public Form1() {
        InitializeComponent();
        InitData();
    }

    void InitData() {
        Node tlDataSource = new Node(null, null);
        // The first root node. 
        Node rootNode1 = new Node(tlDataSource, new string[] { "CEO", "High" });
        Node node1 = new Node(rootNode1, new string[] { "Sales", "Normal" });
        Node node2 = new Node(node1, new string[] { "Direct vs Online Sales Comparison Report", "High" });
        Node node3 = new Node(node1, new string[] { "Training Events", "Low" });
        // The second root node. 
        Node rootNode2 = new Node(tlDataSource, new string[] { "HR department", "High" });
        Node node4 = new Node(rootNode2, new string[] { "Update Employee Files with New NDA", "High" });
        TreeListColumn colName = new TreeListColumn();
        colName.Caption = "Name";
        colName.VisibleIndex = 0;
        TreeListColumn colRank = new TreeListColumn();
        colRank.Caption = "Rank";
        colRank.VisibleIndex = 1;
        treeList1.Columns.AddRange(new TreeListColumn[] { colName, colRank });
        treeList1.DataSource = tlDataSource;
    }
}
vb
Partial Public Class Form1
    Public Sub New()
        InitializeComponent()
    End Sub

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        InitData()
    End Sub

    Sub InitData()
        Dim tlDataSource = New Node(Nothing, Nothing)
        Dim rootNode1 = New Node(tlDataSource, New String() {"CEO", "High"})
        Dim node1 = New Node(rootNode1, New String() {"Sales", "Normal"})
        Dim node2 = New Node(node1, New String() {"Direct vs Online Sales Comparison Report", "High"})
        Dim node3 = New Node(node1, New String() {"Training Events", "Low"})
        Dim rootNode2 = New Node(tlDataSource, New String() {"HR department", "Normal"})
        Dim node4 = New Node(rootNode2, New String() {"Update Employee Files with New NDA", "High"})
        Dim colName As TreeListColumn = New TreeListColumn()
        colName.Caption = "Name"
        colName.VisibleIndex = 0
        Dim colRank As TreeListColumn = New TreeListColumn()
        colRank.Caption = "Rank"
        colRank.VisibleIndex = 1
        TreeList1.Columns.AddRange(New TreeListColumn() {colName, colRank})
        TreeList1.DataSource = tlDataSource
    End Sub
End Class

The image below illustrates the result.

Node Check States

You can use the TreeListOptionsView.CheckBoxStyle, TreeListOptionsView.RootCheckBoxStyle, and TreeListNode.ChildrenCheckBoxStyle properties to enable built-in check boxes that allow end-users to check certain nodes. In this case, you can set the TreeListOptionsBehavior.AllowBoundCheckBoxesInVirtualMode property to true to use the IVirtualTreeListData.VirtualTreeGetCellValue and VirtualTreeSetCellValue methods to specify not only node values, but also node check states.

When the TreeListOptionsBehavior.AllowBoundCheckBoxesInVirtualMode property is true , the IVirtualTreeListData.VirtualTreeGetCellValue interface method additionally fires for each node with the VirtualTreeGetCellValueInfo.IsCheckState parameter set to true. To provide a node’s check state, assign it to the VirtualTreeGetCellValueInfo.CellData parameter (when IsCheckState is true ).

Similarly, when an end-user modifies a node’s check state, the IVirtualTreeListData.VirtualTreeSetCellValue interface method fires with the VirtualTreeSetCellValueInfo.IsCheckState parameter set to true. In this case, save the node’s check state (which is stored in the VirtualTreeSetCellValueInfo.NewCellData parameter) according to your logic.