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

  • 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.


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; }
    }
}

treelist-hierarchalBusinessObject

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.

    • IVirtualTreeListData.VirtualTreeGetChildNodes - Implement this method to provide a child object list to create child nodes.
    • IVirtualTreeListData.VirtualTreeGetCellValue - This method must provide data for the specified node cells (and optionally provide node check states - see the Node Check States section below to learn more).
  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.

    • IVirtualTreeListData.VirtualTreeSetCellValue - This method provides the info.NewCellData parameter that specifies the new value. Typically, you need to save this value to your business object. However, you can discard the value by setting the info.Cancel parameter to true
  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.


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;
    }
}

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


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;
    }
}

The image below illustrates the result.

VirtualTreeInterface

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.