Changing the layout of a WPF TreeView to look like multiple ListBox

Last week at work I was requested to create a new control which should have the behavior of the WPF treeview with a template involving multiple ListBox. To understand what I mean, I wanted to change the layout of this:

To this:

Of course, selection must work properly:

I asked a question on StackOverflow about this control because I didn’t find any easy way to do it. I though at the beginning that playing with the templates of the TreeView and TreeViewItem would do the trick but it didn’t.

The solution I finally choose involves creating multiple ListBox and wire them together using DataBinding:

  • I create a new CustomControl which inherits Control (I couldn’t use neither Selector or TreeView because I wouldn’t have been able to manage the SelectedItem property from the derived class)
  • In the template of this CustomControl is an ItemsControl. This ItemsControl has its ItemTemplate property set to a DataTemplate containing a ListBox.
  • The CustomControl has a Depth property of type int. This property indicates the number of ListBox that should be generated.
  • The CustomControl automatically databound ListBoxes together: each ListBox’s ItemsSource property is databound to the SelectedItem’s children property of the previous ListBox in the visual tree.
  • The CustomControl has a SelectedItem property and a SelectionChanged event (like Selector-derived class).
  • I added an IsReallySelected attached property to the ListBoxItem which are generated. This enables to databing an IsSelected property of the ViewModel class behind the control with the IsSelected of the ListBoxItem. I had to create an attached property because its value is true when the ListBoxItem is selected AND the parent ListBox has IsSelectionActive set to true.

Here is the result:

You can download the source code of this sample (VS2010 RC solution).

3 thoughts on “Changing the layout of a WPF TreeView to look like multiple ListBox

  1. this is fantastic, is it possible to only show the next listbox if the item has children?

    so it would start with a single list box and then grow out?

    cheers.
    ste.

  2. Hi Ste,

    I think yes it should be possible to do that. You might try to bind the Visiblity of the listbox to the HasItems property of the ListBox using a BooleanToVisibility converter.

    Regards,
    Jeremy

  3. Thanks for the fast reply Jeremy.. I could’nt get it work..

    private void SetupBindings()
    {
    // retrieve all ListBox which have been generated
    var listboxes = TreeHelper.FindVisualChildren(this);

    // setup bindings properly between each ListBox
    for (int i = 0; i < listboxes.Count; i++)
    {
    var binding = new Binding();

    var expression = this.GetBindingExpression(ItemsSourceProperty);
    var path = expression.ParentBinding.Path.Path;

    if (i == 0)
    {
    binding.Path = new PropertyPath("ItemsSource");
    binding.Source = this;
    }
    else
    {
    binding.Path = new PropertyPath("SelectedItem." + path);
    binding.Source = listboxes[i – 1];

    Binding visBinding = new Binding();
    visBinding.Path = new PropertyPath("SelectedItem.HasChildren");
    visBinding.Source = listboxes[i – 1];

    listboxes[i].SetBinding(ItemsControl.VisibilityProperty, visBinding);
    }

    listboxes[i].SetBinding(ItemsControl.ItemsSourceProperty, binding);
    }
    }

    any ideas?

    ste.

Leave a Reply

Your email address will not be published. Required fields are marked *