windowsforms-2486-controls-and-libraries-tree-list-feature-center-data-binding-virtual-mode-binding-to-a-hierarchical-business-object-data-source-level.md
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).
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:
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.
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; }
}
}
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
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.
Create a business object that supports the DevExpress.XtraTreeList.IVirtualTreeListData interface, and handle the following two interface methods.
If you need to save changes made by an end-user while editing node cells and node check states, implement the following interface method.
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.
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;
}
}
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.
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;
}
}
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.
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.