Unbound Mode

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

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.

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

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.

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