Back to Devexpress

Unbound Mode

wpf-9567-controls-and-libraries-data-grid-display-hierarchical-data-unbound-mode.md

latest13.5 KB
Original Source

Unbound Mode

  • Oct 03, 2022
  • 6 minutes to read

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

Build a Tree in Unbound Mode

This example creates a TreeListView that operates in unbound mode without a data source.

View Example: Create an Unbound Tree

In XAML

xaml
<dxg:GridControl>
    <dxg:GridColumn FieldName="Name"/>
    <dxg:GridColumn FieldName="Executor"/>
    <dxg:GridColumn FieldName="State"/>
    <dxg:GridControl.View>
        <dxg:TreeListView x:Name="view" AutoWidth="True" AutoExpandAllNodes="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>
cs
public class ProjectObject {
    public string Name { get; set; }
    public string Executor { get; set; }
}

public class StageObject : ProjectObject { }

public class TaskObject : ProjectObject {
    public string State { get; set; }
}
vb
Public Class ProjectObject

    Public Property Name As String

    Public Property Executor As String
End Class

Public Class StageObject
    Inherits ProjectObject

End Class

Public Class TaskObject
    Inherits ProjectObject

    Public Property State As String
End Class

In Code

xaml
<dxg:GridControl>
    <dxg:GridColumn FieldName="Name"/>
    <dxg:GridColumn FieldName="Executor"/>
    <dxg:GridColumn FieldName="State"/>
    <dxg:GridControl.View>
        <dxg:TreeListView x:Name="view" AutoWidth="True" AutoExpandAllNodes="True"/>
    </dxg:GridControl.View>
</dxg:GridControl>
csharp
public partial class MainWindow : Window {
    public MainWindow() {
        // ...
        BuildTree();
    }

    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);
        view.Nodes.Add(rootNode);
        return rootNode;
    }

    private TreeListNode CreateChildNode(TreeListNode parentNode, object dataObject) {
        TreeListNode childNode = new TreeListNode(dataObject);
        parentNode.Nodes.Add(childNode);
        return childNode;
    }
}
vb
Public Partial Class MainWindow
    Inherits Window

    Public Sub New()
        ' ...
        BuildTree();
    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 TreeListNode = New TreeListNode(dataObject)
        Me.view.Nodes.Add(rootNode)
        Return rootNode
    End Function

    Private Function CreateChildNode(ByVal parentNode As TreeListNode, ByVal dataObject As Object) As TreeListNode
        Dim childNode As TreeListNode = New TreeListNode(dataObject)
        parentNode.Nodes.Add(childNode)
        Return childNode
    End Function
End Class

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.

Load Data On-Demand

In this example, the TreeListView displays the file/folder tree. The TreeListView.NodeExpanding event allows you to create child nodes dynamically when a user expands a parent node.

View Example: Load Nodes Dynamically

xaml
<dxg:GridControl x:Name="grid">
    <dxg:GridControl.Columns>
        <dxg:GridColumn FieldName="Name"/>
        <dxg:GridColumn FieldName="ItemType"/>
        <dxg:GridColumn FieldName="Size">
            <dxg:GridColumn.EditSettings>
                <dxe:TextEditSettings HorizontalContentAlignment="Right"/>
            </dxg:GridColumn.EditSettings>
        </dxg:GridColumn>
        <dxg:GridColumn FieldName="FullName"/>
    </dxg:GridControl.Columns>
    <dxg:GridControl.View>
        <dxg:TreeListView x:Name="view" 
                          AllowEditing="False"
                          AutoWidth="True"
                          NodeExpanding="OnNodeExpanding"/>
    </dxg:GridControl.View>
</dxg:GridControl>
cs
public partial class MainWindow : Window {
    FileSystemDataProvider Helper { get; set; }
    public MainWindow() {
        InitializeComponent();
        Helper = new FileSystemHelper();
        InitDrives();
    }
    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) };
                view.Nodes.Add(node);
                node.IsExpandButtonVisible = DefaultBoolean.True;
            }
        }
        catch { }
        grid.EndDataUpdate();
    }

    private void OnNodeExpanding(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;
        }
    }

    private void InitFolder(TreeListNode treeListNode) {
        grid.BeginDataUpdate();
        InitFolders(treeListNode);
        InitFiles(treeListNode);
        grid.EndDataUpdate();
    }

    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 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 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;
    }
}
vb
Public Partial Class MainWindow
    Inherits Window

    Private Property Helper As FileSystemDataProvider

    Public Sub New()
        Me.InitializeComponent()
        Helper = New FileSystemHelper()
        InitDrives()
    End Sub

    Public Sub InitDrives()
        Me.grid.BeginDataUpdate()
        Try
            Dim root As String() = Helper.GetLogicalDrives()
            For Each s As String In root
                Dim node As TreeListNode = New TreeListNode() With {.Content = New FileSystemItem(s, "Drive", "<Drive>", s)}
                Me.view.Nodes.Add(node)
                node.IsExpandButtonVisible = DefaultBoolean.True
            Next
        Catch
        End Try

        Me.grid.EndDataUpdate()
    End Sub

    Private Sub OnNodeExpanding(ByVal sender As Object, ByVal e As 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 Sub InitFolder(ByVal treeListNode As TreeListNode)
        Me.grid.BeginDataUpdate()
        InitFolders(treeListNode)
        InitFiles(treeListNode)
        Me.grid.EndDataUpdate()
    End Sub

    Private Sub InitFolders(ByVal treeListNode As TreeListNode)
        Dim item As FileSystemItem = TryCast(treeListNode.Content, FileSystemItem)
        If item Is Nothing Then Return
        Try
            Dim root As String() = Helper.GetDirectories(item.FullName)
            For Each s As String In root
                Try
                    Dim node As TreeListNode = 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
        Catch
        End Try
    End Sub

    Private Sub InitFiles(ByVal treeListNode As TreeListNode)
        Dim item As FileSystemItem = TryCast(treeListNode.Content, FileSystemItem)
        If item Is Nothing Then Return
        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
        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
        root = Helper.GetDirectories(path)
        If root.Length > 0 Then Return True
        Return False
    End Function
End Class