Search Results for

    Show / Hide Table of Contents

    Tree View

    WpfTreeView is a WPF control for displaying a hierarchical view of objects, optionally with additional user interface elements such as check boxes.

    The tree view is controlled by a model object, which can be a WpfTreeModel or a subclass thereof.

    Each node in the view is represented by a WpfTreeNode or a subclass thereof.

    Basic tree view

    This section describes how to create a tree view with no extra UI besides the tree nodes, and how to perform drag and drop operations.

    Example

    The XAML for a basic tree view is simple; no markup us required besides the <WpfTreeView> element. The code-behind for the tree view creates a tree model with some nodes and assigns it to the tree view.

    We use a subclassed tree model to handle drag & drop operations by overriding the virtual methods GetDropTargetFeedback and Drop.

    <Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:rs="clr-namespace:ABB.Robotics.RobotStudio.UI;assembly=ABB.Robotics.RobotStudio.UI"
        Title="MainWindow" Height="400" Width="300">
      <Grid>
        <rs:WpfTreeView Name="_treeView"/>
      </Grid>
    </Window>
    
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        MyTreeModel _treeModel;
        
        public MainWindow()
        {
            InitializeComponent();
            
            // Create the tree model
            _treeModel = new MyTreeModel();
            _treeModel.ExpandRootNodes = true;
            // Add some nodes
            BitmapImage image = new BitmapImage(new Uri(@"pack://application:,,,/Resources/Image1.png"));
            _treeModel.Root.Children.AddRange(new[]
            {
                new WpfTreeNode("Node1", image, new[]
                {
                    new WpfTreeNode("Node2", image),
                    new WpfTreeNode("Node3", image, new[]
                    {
                        new WpfTreeNode("Node4", image),
                        new WpfTreeNode("Node5", image)
                    })
                }),
                new WpfTreeNode("Node6", image)
            });
            // Assign the tree model to the view
            _treeView.TreeModel = _treeModel;
        }
    }
    
    /// <summary>
    /// Tree model with drag & drop support
    /// </summary>
    class MyTreeModel : WpfTreeModel
    {
        /// <summary>
        /// Called when the user drags object(s) over a node in the tree.
        /// </summary>
        protected override DropTargetFeedback GetDropTargetFeedback(object target, object[] draggedObjects, bool copy)
        {
            if (draggedObjects.Length != 1) return DropTargetFeedback.None;
            var draggedNode = draggedObjects[0] as WpfTreeNode;
            if (draggedNode == null) return DropTargetFeedback.None;
            
            var targetNode = target as WpfTreeNode;
            if (targetNode.Ancestors(false).Contains(draggedNode)) return DropTargetFeedback.None;
            
            if (draggedNode.Parent == targetNode.Parent)
            {
                // Sibling node -- reorder nodes
                return DropTargetFeedback.InsertAfter;
            }
            else
            {
                // Other node -- move to new parent
                return DropTargetFeedback.CanDrop;
            }
        }
        
        /// <summary>
        /// Called when the user drops object(s) over a node in the tree.
        /// </summary>
        protected override void Drop(object target, object[] draggedObjects, bool copy)
        {
            var targetNode = target as WpfTreeNode;
            var draggedNode = draggedObjects[0] as WpfTreeNode;
            if (draggedNode.Parent == targetNode.Parent)
            {
                // Sibling node -- reorder nodes
                draggedNode.Remove();
                var targetParent = targetNode.Parent;
                int idx = targetParent.Children.IndexOf(targetNode);
                targetParent.Children.Insert(idx + 1, draggedNode);
                targetParent.Children.DisplayOrder = DisplayOrder.AsIs;
            }
            else
            {
                // Other node -- move to new parent
                draggedNode.Remove();
                targetNode.Children.Insert(0, draggedNode);
                targetNode.Children.DisplayOrder = DisplayOrder.AsIs;
            }
        }
    }
    

    Grid-style tree view

    This section describes how to create a grid-style tree view with headers and additional controls for each node.

    Example

    The grid style is enabled by defining the attribute GridMode in the WpfTreeView element.

    The columns and their content are defined by GridViewColumns. By using the subclass GridViewSortColumn, the tree view can be automatically sorted when the user clicks the column header.

    When databinding to the tree node objects, the syntax Object.<Property> must be used.

    <Window x:Class="WpfApplication2.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:rs="clr-namespace:ABB.Robotics.RobotStudio.UI;assembly=ABB.Robotics.RobotStudio.UI"
        Title="MainWindow" Height="400" Width="300">
      <Grid>
        <rs:WpfTreeView Name="_treeView" GridMode="True" FirstColumnHeader="Object" FirstColumnWidth="150">
        <rs:WpfTreeView.Columns>
        <GridViewColumn Header="Check" Width="100">
        <GridViewColumn.CellTemplate>
        <DataTemplate>
          <CheckBox IsChecked="{Binding Path=Object.IsChecked}" IsThreeState="True" IsEnabled="{Binding Path=Object.CheckBoxEnabled}" />
          </DataTemplate>
            </GridViewColumn.CellTemplate>
            </GridViewColumn>
            <rs:GridViewSortColumn Header="Color" Width="100" SortProperty="Object.Color">
            <rs:GridViewSortColumn.CellTemplate>
          <DataTemplate>
            <ComboBox SelectedValue="{Binding Path=Object.Color}" Visibility="{Binding Path=Object.ColorVisibility}">
            <ComboBoxItem>Red</ComboBoxItem>
            <ComboBoxItem>Green</ComboBoxItem>
            <ComboBoxItem>Blue</ComboBoxItem>
            </ComboBox>
          </DataTemplate>
        </rs:GridViewSortColumn.CellTemplate>
        </rs:GridViewSortColumn>
        </rs:WpfTreeView.Columns>
        </rs:WpfTreeView>
      </Grid>
    </Window>
    

    The code-behind for the tree view demonstrates to add headers to the view, and how to subscribe on the NodePropertyChanged event that is raised when a node property changes.

    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        WpfTreeModel _treeModel;
        
        public MainWindow()
        {
            InitializeComponent();
            
            // Create the tree model
            _treeModel = new WpfTreeModel();
            // Assign the model to the tree
            _treeView.TreeModel = _treeModel;
            
            // Add some nodes and a header
            var root = new MyTreeNode("Root") { StartExpanded = true };
            var header = new WpfTreeHeader("Colors");
            root.Children.Add(new MyTreeNode("Node1") { Color = "Red", Header = header });
            root.Children.Add(new MyTreeNode("Node2") { Color = "Blue", Header = header, IsChecked = true });
            _treeModel.Root.Children.Add(root);
    
            // Subscribe to node property change events
            _treeModel.NodePropertyChanged += _treeModel_NodePropertyChanged;
        }
    
        void _treeModel_NodePropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            var node = sender as WpfTreeNode;
            System.Diagnostics.Trace.WriteLine(string.Format("NodePropertyChanged({0}, {1})", node.Text, e.PropertyName));
        }
    }
    

    To add additional properties to the tree nodes, we use a subclassed node type.

    In this sample, we base the class on WpfCheckedTreeNode which provides additional functionality for propagating the IsChecked property up and down the tree.

    The base class provides an OnPropertyChanged method for raising the PropertyChanged event used by WPF databinding.

    /// <summary>
    /// Tree node with additional properties
    /// </summary>
    class MyTreeNode : WpfCheckedTreeNode
    {
        string _color;
        static BitmapImage _image = new BitmapImage(new Uri(@"pack://application:,,,/Resources/Image1.png"));
        
        public MyTreeNode(string text) :
        base(text, _image)
        {
        }
        
        public string Color
        {
            get
            {
                return _color;
            }
            set
            {
                _color = value;
                // Notify subscribers
                OnPropertyChanged("Color");
            }
        }
    
        public Visibility ColorVisibility
        {
            get
            {
                // Hide the color combo-box if Color is empty
                return string.IsNullOrEmpty(_color) ? Visibility.Hidden : Visibility.Visible;
            }
        }
    }
    
    In this article
    Back to top Copyright © 2026 ABB Robotics