Nodes are stored as nested collections because the TreeListView displays data in a tree. The collection of root level nodes can be accessed via the TreeListView.Nodes property. Each node has its own collection of child nodes available via the TreeListNode.Nodes property. These child nodes have their own children, etc.
In an unbound mode, you should manually build a TREE by creating nodes (TreeListNode) and adding them to the corresponding node collections.
Note
Nodes can be represented by objects of different types. The only requirement is that these data objects should have common fields (columns).
Example: How to Manually Create a Tree (Unbound Mode)
This example shows how to manually create a tree (unbound mode). It is shown how to create nodes in XAML and code.
View Example
using System;
using System.Windows;
using DevExpress.Xpf.Grid;
namespace TreeListView_UnboundMode {
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window {
public MainWindow() {
InitializeComponent();
BuildTree();
treeListView1.ExpandAllNodes();
}
private void BuildTree() {
TreeListNode rootNode = CreateRootNode(new ProjectObject() { Name = "Project: Stanton", Executor = "Nicholas Llams" });
TreeListNode childNode = CreateChildNode(rootNode, new StageObject() { Name = "Information Gathering", Executor = "Ankie Galva" });
CreateChildNode(childNode, new TaskObject() { Name = "Design", Executor = "Reardon Felton", State = "In progress" });
}
private TreeListNode CreateRootNode(object dataObject) {
TreeListNode rootNode = new TreeListNode(dataObject);
treeListView1.Nodes.Add(rootNode);
return rootNode;
}
private TreeListNode CreateChildNode(TreeListNode parentNode, object dataObject) {
TreeListNode childNode = new TreeListNode(dataObject);
parentNode.Nodes.Add(childNode);
return childNode;
}
}
public class StageObject {
public String Name { get; set; }
public string Executor { get; set; }
}
public class ProjectObject {
public String Name { get; set; }
public string Executor { get; set; }
}
public class TaskObject {
public String Name { get; set; }
public string Executor { get; set; }
public string State { get; set; }
}
}
<Window x:Class="TreeListView_UnboundMode.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525"
xmlns:dxg="http://schemas.devexpress.com/winfx/2008/xaml/grid"
xmlns:local="clr-namespace:TreeListView_UnboundMode">
<Grid>
<dxg:GridControl Name="grid">
<dxg:GridControl.Columns>
<dxg:GridColumn FieldName="Name" />
<dxg:GridColumn FieldName="Executor" />
<dxg:GridColumn FieldName="State" />
</dxg:GridControl.Columns>
<dxg:GridControl.View>
<dxg:TreeListView Name="treeListView1" AutoWidth="True">
<dxg:TreeListView.Nodes>
<dxg:TreeListNode>
<dxg:TreeListNode.Content>
<local:ProjectObject Name="Project: Betaron" Executor="Destiny Tabisola" />
</dxg:TreeListNode.Content>
<dxg:TreeListNode.Nodes>
<dxg:TreeListNode>
<dxg:TreeListNode.Content>
<local:StageObject Name="Development" Executor="Kairra Hogg" />
</dxg:TreeListNode.Content>
<dxg:TreeListNode.Nodes>
<dxg:TreeListNode>
<dxg:TreeListNode.Content>
<local:TaskObject Name="Coding" Executor="Sabato Durley" State="Not Started" />
</dxg:TreeListNode.Content>
</dxg:TreeListNode>
</dxg:TreeListNode.Nodes>
</dxg:TreeListNode>
</dxg:TreeListNode.Nodes>
</dxg:TreeListNode>
</dxg:TreeListView.Nodes>
</dxg:TreeListView>
</dxg:GridControl.View>
</dxg:GridControl>
</Grid>
</Window>
Imports Microsoft.VisualBasic
Imports System
Imports System.Windows
Imports DevExpress.Xpf.Grid
Namespace TreeListView_UnboundMode
''' <summary>
''' Interaction logic for MainWindow.xaml
''' </summary>
Partial Public Class MainWindow
Inherits Window
Public Sub New()
InitializeComponent()
BuildTree()
treeListView1.ExpandAllNodes()
End Sub
Private Sub BuildTree()
Dim rootNode As TreeListNode = CreateRootNode(New ProjectObject() With {.Name = "Project: Stanton", .Executor = "Nicholas Llams"})
Dim childNode As TreeListNode = CreateChildNode(rootNode, New StageObject() With {.Name = "Information Gathering", .Executor = "Ankie Galva"})
CreateChildNode(childNode, New TaskObject() With {.Name = "Design", .Executor = "Reardon Felton", .State = "In progress"})
End Sub
Private Function CreateRootNode(ByVal dataObject As Object) As TreeListNode
Dim rootNode As New TreeListNode(dataObject)
treeListView1.Nodes.Add(rootNode)
Return rootNode
End Function
Private Function CreateChildNode(ByVal parentNode As TreeListNode, ByVal dataObject As Object) As TreeListNode
Dim childNode As New TreeListNode(dataObject)
parentNode.Nodes.Add(childNode)
Return childNode
End Function
End Class
Public Class StageObject
Private privateName As String
Public Property Name() As String
Get
Return privateName
End Get
Set(ByVal value As String)
privateName = value
End Set
End Property
Private privateExecutor As String
Public Property Executor() As String
Get
Return privateExecutor
End Get
Set(ByVal value As String)
privateExecutor = value
End Set
End Property
End Class
Public Class ProjectObject
Private privateName As String
Public Property Name() As String
Get
Return privateName
End Get
Set(ByVal value As String)
privateName = value
End Set
End Property
Private privateExecutor As String
Public Property Executor() As String
Get
Return privateExecutor
End Get
Set(ByVal value As String)
privateExecutor = value
End Set
End Property
End Class
Public Class TaskObject
Private privateName As String
Public Property Name() As String
Get
Return privateName
End Get
Set(ByVal value As String)
privateName = value
End Set
End Property
Private privateExecutor As String
Public Property Executor() As String
Get
Return privateExecutor
End Get
Set(ByVal value As String)
privateExecutor = value
End Set
End Property
Private privateState As String
Public Property State() As String
Get
Return privateState
End Get
Set(ByVal value As String)
privateState = value
End Set
End Property
End Class
End Namespace
Dynamic Data Loading
In an unbound mode, you need to manually create a tree (in code or XAML). A tree can be created on demand. Child nodes are dynamically created and initialized when their parent node is expanded.
To implement on demand node loading, handle the TreeListView.NodeExpanding event. This event occurs before a node is expanded, allowing you to dynamically populate its collection of child nodes. The processed node is returned by the event parameter’s TreeListNodeEventArgs.Node property.
Note
When expanding a node, you do not know whether it has child nodes or not. If the node has no child nodes, hide the expand button by setting the TreeListNode.IsExpandButtonVisible property to false.
Example: How to Implement On-Demand Data Loading
In this example, the TreeListView displays the file/folder tree. Child nodes that correspond to sub folders or files contained within a folder are dynamically created when a parent node is being expanded.
View Example
<Window x:Class="DynamicNodeLoading.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525" xmlns:dxg="http://schemas.devexpress.com/winfx/2008/xaml/grid">
<Grid>
<dxg:GridControl Name="grid">
<dxg:GridControl.Columns>
<dxg:GridColumn FieldName="Name" />
<dxg:GridColumn FieldName="ItemType" />
<dxg:GridColumn FieldName="Size" />
<dxg:GridColumn FieldName="FullName" />
</dxg:GridControl.Columns>
<dxg:GridControl.View>
<dxg:TreeListView Name="treeListView1" AutoWidth="True"
NodeExpanding="treeListView1_NodeExpanding"/>
</dxg:GridControl.View>
</dxg:GridControl>
</Grid>
</Window>
using System;
using System.Windows;
using DevExpress.Xpf.Grid;
using System.IO;
using DevExpress.Utils;
namespace DynamicNodeLoading {
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window {
public MainWindow() {
InitializeComponent();
Helper = new FileSystemHelper();
InitDrives();
}
private void treeListView1_NodeExpanding(object sender, DevExpress.Xpf.Grid.TreeList.TreeListNodeAllowEventArgs e) {
TreeListNode node = e.Node;
if (node.Tag == null || (bool)node.Tag == false) {
InitFolder(node);
node.Tag = true;
}
}
FileSystemDataProvider Helper { get; set; }
public void InitDrives() {
grid.BeginDataUpdate();
try {
string[] root = Helper.GetLogicalDrives();
foreach (string s in root) {
TreeListNode node = new TreeListNode() { Content = new FileSystemItem(s, "Drive", "<Drive>", s) };
treeListView1.Nodes.Add(node);
node.IsExpandButtonVisible = DefaultBoolean.True;
}
}
catch { }
grid.EndDataUpdate();
}
private void InitFolder(TreeListNode treeListNode) {
grid.BeginDataUpdate();
InitFolders(treeListNode);
InitFiles(treeListNode);
grid.EndDataUpdate();
}
private void InitFiles(TreeListNode treeListNode) {
FileSystemItem item = treeListNode.Content as FileSystemItem;
if (item == null) return;
TreeListNode node;
try {
string[] root = Helper.GetFiles(item.FullName);
foreach (string s in root) {
node = new TreeListNode() { Content = new FileSystemItem(Helper.GetFileName(s), "File", Helper.GetFileSize(s).ToString(), s) };
node.IsExpandButtonVisible = DefaultBoolean.False;
treeListNode.Nodes.Add(node);
}
}
catch { }
}
private void InitFolders(TreeListNode treeListNode) {
FileSystemItem item = treeListNode.Content as FileSystemItem;
if (item == null) return;
try {
string[] root = Helper.GetDirectories(item.FullName);
foreach (string s in root) {
try {
TreeListNode node = new TreeListNode() { Content = new FileSystemItem(Helper.GetDirectoryName(s), "Folder", "<Folder>", s) };
treeListNode.Nodes.Add(node);
node.IsExpandButtonVisible = HasFiles(s) ? DefaultBoolean.True : DefaultBoolean.False;
}
catch { }
}
}
catch { }
}
private bool HasFiles(string path) {
string[] root = Helper.GetFiles(path);
if (root.Length > 0) return true;
root = Helper.GetDirectories(path);
if (root.Length > 0) return true;
return false;
}
public abstract class FileSystemDataProvider {
public abstract string[] GetLogicalDrives();
public abstract string[] GetDirectories(string path);
public abstract string[] GetFiles(string path);
public abstract string GetDirectoryName(string path);
public abstract string GetFileName(string path);
public abstract long GetFileSize(string path);
}
public class FileSystemHelper : FileSystemDataProvider {
public override string[] GetLogicalDrives() {
return Directory.GetLogicalDrives();
}
public override string[] GetDirectories(string path) {
return Directory.GetDirectories(path);
}
public override string[] GetFiles(string path) {
return Directory.GetFiles(path);
}
public override string GetDirectoryName(string path) {
return new DirectoryInfo(path).Name;
}
public override string GetFileName(string path) {
return new FileInfo(path).Name;
}
public override long GetFileSize(string path) {
return new FileInfo(path).Length;
}
}
}
public class FileSystemItem {
public FileSystemItem(string name, string type, string size, string fullName) {
Name = name;
ItemType = type;
Size = size;
FullName = fullName;
}
public string Name { get; set; }
public string ItemType { get; set; }
public string Size { get; set; }
public string FullName { get; set; }
}
}
Imports Microsoft.VisualBasic
Imports System
Imports System.Windows
Imports DevExpress.Xpf.Grid
Imports System.IO
Imports DevExpress.Utils
Namespace DynamicNodeLoading
''' <summary>
''' Interaction logic for MainWindow.xaml
''' </summary>
Partial Public Class MainWindow
Inherits Window
Public Sub New()
InitializeComponent()
Helper = New FileSystemHelper()
InitDrives()
End Sub
Private Sub treeListView1_NodeExpanding(ByVal sender As Object, ByVal e As DevExpress.Xpf.Grid.TreeList.TreeListNodeAllowEventArgs)
Dim node As TreeListNode = e.Node
If node.Tag Is Nothing OrElse CBool(node.Tag) = False Then
InitFolder(node)
node.Tag = True
End If
End Sub
Private privateHelper As FileSystemDataProvider
Private Property Helper() As FileSystemDataProvider
Get
Return privateHelper
End Get
Set(ByVal value As FileSystemDataProvider)
privateHelper = value
End Set
End Property
Public Sub InitDrives()
grid.BeginDataUpdate()
Try
Dim root() As String = Helper.GetLogicalDrives()
For Each s As String In root
Dim node As New TreeListNode() With {.Content = New FileSystemItem(s, "Drive", "<Drive>", s)}
treeListView1.Nodes.Add(node)
node.IsExpandButtonVisible = DefaultBoolean.True
Next s
Catch
End Try
grid.EndDataUpdate()
End Sub
Private Sub InitFolder(ByVal treeListNode As TreeListNode)
grid.BeginDataUpdate()
InitFolders(treeListNode)
InitFiles(treeListNode)
grid.EndDataUpdate()
End Sub
Private Sub InitFiles(ByVal treeListNode As TreeListNode)
Dim item As FileSystemItem = TryCast(treeListNode.Content, FileSystemItem)
If item Is Nothing Then
Return
End If
Dim node As TreeListNode
Try
Dim root() As String = Helper.GetFiles(item.FullName)
For Each s As String In root
node = New TreeListNode() With {.Content = New FileSystemItem(Helper.GetFileName(s), "File", Helper.GetFileSize(s).ToString(), s)}
node.IsExpandButtonVisible = DefaultBoolean.False
treeListNode.Nodes.Add(node)
Next s
Catch
End Try
End Sub
Private Sub InitFolders(ByVal treeListNode As TreeListNode)
Dim item As FileSystemItem = TryCast(treeListNode.Content, FileSystemItem)
If item Is Nothing Then
Return
End If
Try
Dim root() As String = Helper.GetDirectories(item.FullName)
For Each s As String In root
Try
Dim node As New TreeListNode() With {.Content = New FileSystemItem(Helper.GetDirectoryName(s), "Folder", "<Folder>", s)}
treeListNode.Nodes.Add(node)
node.IsExpandButtonVisible = If(HasFiles(s), DefaultBoolean.True, DefaultBoolean.False)
Catch
End Try
Next s
Catch
End Try
End Sub
Private Function HasFiles(ByVal path As String) As Boolean
Dim root() As String = Helper.GetFiles(path)
If root.Length > 0 Then
Return True
End If
root = Helper.GetDirectories(path)
If root.Length > 0 Then
Return True
End If
Return False
End Function
Public MustInherit Class FileSystemDataProvider
Public MustOverride Function GetLogicalDrives() As String()
Public MustOverride Function GetDirectories(ByVal path As String) As String()
Public MustOverride Function GetFiles(ByVal path As String) As String()
Public MustOverride Function GetDirectoryName(ByVal path As String) As String
Public MustOverride Function GetFileName(ByVal path As String) As String
Public MustOverride Function GetFileSize(ByVal path As String) As Long
End Class
Public Class FileSystemHelper
Inherits FileSystemDataProvider
Public Overrides Function GetLogicalDrives() As String()
Return Directory.GetLogicalDrives()
End Function
Public Overrides Function GetDirectories(ByVal path As String) As String()
Return Directory.GetDirectories(path)
End Function
Public Overrides Function GetFiles(ByVal path As String) As String()
Return Directory.GetFiles(path)
End Function
Public Overrides Function GetDirectoryName(ByVal path As String) As String
Return New DirectoryInfo(path).Name
End Function
Public Overrides Function GetFileName(ByVal path As String) As String
Return New FileInfo(path).Name
End Function
Public Overrides Function GetFileSize(ByVal path As String) As Long
Return New FileInfo(path).Length
End Function
End Class
End Class
Public Class FileSystemItem
Public Sub New(ByVal name As String, ByVal type As String, ByVal size As String, ByVal fullName As String)
Name = name
ItemType = type
Size = size
FullName = fullName
End Sub
Private privateName As String
Public Property Name() As String
Get
Return privateName
End Get
Set(ByVal value As String)
privateName = value
End Set
End Property
Private privateItemType As String
Public Property ItemType() As String
Get
Return privateItemType
End Get
Set(ByVal value As String)
privateItemType = value
End Set
End Property
Private privateSize As String
Public Property Size() As String
Get
Return privateSize
End Get
Set(ByVal value As String)
privateSize = value
End Set
End Property
Private privateFullName As String
Public Property FullName() As String
Get
Return privateFullName
End Get
Set(ByVal value As String)
privateFullName = value
End Set
End Property
End Class
End Namespace