Unbound Mode
- 8 minutes to read
The Tree List control supports unbound mode, in which you can manually create nodes. Unbound mode implies that the TreeList.DataSource property is set to null.
Tip
Use the following binding modes if the TreeList control’s underlying data dynamically changes, and the control should reflect these changes immediately:
The bound data source needs to implement the INotifyPropertyChanged
interface.
Online Video
WinForms Tree List - How to Create a Conventional TreeList.
Add Columns
Before you add nodes in unbound mode, you need to create columns. Use the Tree List Designer to create columns at design time, or utilize the TreeList.Columns collection to add them in code.
Add Nodes
You can use the Nodes Editor to create nodes manually at design time. At runtime, use the TreeList.AppendNode method to create nodes.
The TreeList.AppendNode method has a nodeData parameter. It specifies the data used to initialize the created node cells. The nodeData parameter can be an array of values or a DataRow object. The number and order of items in the array/DataRow object must match the number and order of Tree List columns.
Dynamic Data Loading
You can create all the nodes beforehand (for instance, on form loading). To improve the control’s performance for large volumes of data, you may consider dynamic data loading — create root nodes on form loading and supply child nodes dynamically, on demand, when parent nodes are expanded.
You can implement dynamic loading as follows:
Create root Tree List nodes at design time, or with the TreeList.AppendNode method.
For nodes that have children, set the TreeListNode.HasChildren property to true. The control displays expand buttons for these nodes.
Handle the TreeList.BeforeExpand event to supply children for expanded nodes. For child nodes that have their own children, you also need to set the TreeListNode.HasChildren property to true.
Export and Import Data
In unbound mode, you can export nodes and their data to a stream or file in XML format, and then load it later. To export the data, use the TreeList.ExportToXml method. To import the previously saved data, use the TreeList.ImportFromXml method.
For more information on data export, see the following help topic: Export and Import Data.
Batch Modifications in Code
Every time the TreeList.AppendNode method or another method that modifies the node structure is called, the Tree List control performs an update. If you perform multiple subsequent calls to these methods, multiple updates take place. For performance reasons, you can avoid unnecessary updates by enclosing your code with the TreeList.BeginUnboundLoad and TreeList.EndUnboundLoad methods. In this instance, the control is updated only once, by the EndUnboundLoad
method.
Update Cell Values API
- TreeList.SetRowCellValue — Sets the TreeList cell to a specific value.
- TreeList.GetRowCellValue — Retrieves the value stored within the required cell.
- TreeList.GetRowCellDisplayText — Returns the text displayed by a specific Tree List cell.
Access Nodes API
- TreeList.Nodes — Provides access to the collection of the TreeList’s root nodes.
- TreeListNode.Nodes — Gets the collection of the node’s children.
- TreeListNode.ParentNode — Gets the parent node of the current tree node.
- FindNodeByID — Returns the node specified by its identifier.
- FindNodeByKeyID — Returns the node by its key field value.
- FindNodeByFieldValue — Returns a node by its field value.
Tip
DevExpress controls have consistent UIs and APIs. The Gantt Control, Data Grid, and Vertical Grid have the same-named properties and methods to work with rows (nodes) and cell values.
Example
This example demonstrates how to show the structure of directories and files on your local drive in the Tree List control by implementing node dynamic loading in unbound mode.
using DevExpress.XtraTreeList.Columns;
using DevExpress.XtraTreeList.Nodes;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace TreeList_UnboundMode_ViaBeforeExpandEvent {
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
InitTreeList();
InitData();
}
private void InitTreeList() {
TreeListColumn treeListColumn1 = new TreeListColumn();
TreeListColumn treeListColumn2 = new TreeListColumn();
TreeListColumn treeListColumn3 = new TreeListColumn();
TreeListColumn treeListColumn4 = new TreeListColumn();
//
// treeListColumn1
//
treeListColumn1.Caption = "FullName";
treeListColumn1.FieldName = "FullName";
//
// treeListColumn2
//
treeListColumn2.Caption = "Name";
treeListColumn2.FieldName = "Name";
treeListColumn2.MinWidth = 27;
treeListColumn2.VisibleIndex = 0;
treeListColumn2.Width = 274;
//
// treeListColumn3
//
treeListColumn3.Caption = "Type";
treeListColumn3.FieldName = "Type";
treeListColumn3.VisibleIndex = 1;
treeListColumn3.Width = 112;
//
// treeListColumn4
//
treeListColumn4.AppearanceCell.Options.UseTextOptions = true;
treeListColumn4.AppearanceCell.TextOptions.HAlignment = DevExpress.Utils.HorzAlignment.Far;
treeListColumn4.Caption = "Size(Bytes)";
treeListColumn4.FieldName = "Size";
treeListColumn4.Format.FormatType = DevExpress.Utils.FormatType.Numeric;
treeListColumn4.Format.FormatString = "n0";
treeListColumn4.VisibleIndex = 2;
treeListColumn4.Width = 123;
treeList1.Columns.AddRange(new DevExpress.XtraTreeList.Columns.TreeListColumn[] {
treeListColumn1,
treeListColumn2,
treeListColumn3,
treeListColumn4});
treeList1.Dock = System.Windows.Forms.DockStyle.Fill;
treeList1.OptionsBehavior.AutoChangeParent = false;
treeList1.OptionsBehavior.AutoNodeHeight = false;
treeList1.OptionsBehavior.CloseEditorOnLostFocus = false;
treeList1.OptionsBehavior.Editable = false;
treeList1.OptionsSelection.KeepSelectedOnClick = false;
treeList1.OptionsBehavior.ShowToolTips = false;
treeList1.OptionsBehavior.SmartMouseHover = false;
treeList1.StateImageList = this.imageList1;
treeList1.AfterCollapse += new DevExpress.XtraTreeList.NodeEventHandler(this.treeList1_AfterCollapse);
treeList1.AfterExpand += new DevExpress.XtraTreeList.NodeEventHandler(this.treeList1_AfterExpand);
treeList1.BeforeExpand += new DevExpress.XtraTreeList.BeforeExpandEventHandler(this.treeList1_BeforeExpand);
}
private void InitData() {
InitFolders(Directory.GetDirectoryRoot(Directory.GetCurrentDirectory()), null);
}
private void InitFolders(string path, TreeListNode pNode) {
treeList1.BeginUnboundLoad();
TreeListNode node;
DirectoryInfo di;
try {
string[] root = Directory.GetDirectories(path);
foreach (string s in root) {
try {
di = new DirectoryInfo(s);
node = treeList1.AppendNode(new object[] { s, di.Name, "Folder", null }, pNode);
node.StateImageIndex = 0;
node.HasChildren = HasFiles(s);
if (node.HasChildren)
node.Tag = true;
}
catch { }
}
}
catch { }
InitFiles(path, pNode);
treeList1.EndUnboundLoad();
}
private void InitFiles(string path, TreeListNode pNode) {
TreeListNode node;
FileInfo fi;
try {
string[] root = Directory.GetFiles(path);
foreach (string s in root) {
fi = new FileInfo(s);
node = treeList1.AppendNode(new object[] { s, fi.Name, "File", fi.Length }, pNode);
node.StateImageIndex = 1;
node.HasChildren = false;
}
}
catch { }
}
private bool HasFiles(string path) {
string[] root = Directory.GetFiles(path);
if (root.Length > 0) return true;
root = Directory.GetDirectories(path);
if (root.Length > 0) return true;
return false;
}
private void treeList1_BeforeExpand(object sender, DevExpress.XtraTreeList.BeforeExpandEventArgs e) {
if (e.Node.Tag != null) {
Cursor currentCursor = Cursor.Current;
Cursor.Current = Cursors.WaitCursor;
InitFolders(e.Node.GetDisplayText("FullName"), e.Node);
e.Node.Tag = null;
Cursor.Current = currentCursor;
}
}
private void treeList1_AfterExpand(object sender, DevExpress.XtraTreeList.NodeEventArgs e) {
if (e.Node.StateImageIndex != 1) e.Node.StateImageIndex = 2;
}
private void treeList1_AfterCollapse(object sender, DevExpress.XtraTreeList.NodeEventArgs e) {
if (e.Node.StateImageIndex != 1) e.Node.StateImageIndex = 0;
}
}
}