11

The standard WPF tree view does not support multiple selections.

How can I add a tree view that supports multiple selection to my WPF application? Commercial products are fine (I am currently aware of one commercial implementation - http://www.telerik.com/products/wpf/treeview.aspx)

Justin
  • 84,773
  • 49
  • 224
  • 367
mark
  • 59,016
  • 79
  • 296
  • 580

2 Answers2

14

The code below works fine and is much simpler. However the draw back is the use of the non public property, IsSelectionChangeActive, of the treeview class. Code below:

private static readonly PropertyInfo IsSelectionChangeActiveProperty 
  = typeof (TreeView).GetProperty
    (
      "IsSelectionChangeActive",
      BindingFlags.NonPublic | BindingFlags.Instance
    );

public static void AllowMultiSelection(TreeView treeView)
{
  if (IsSelectionChangeActiveProperty==null) return;

  var selectedItems = new List<TreeViewItem>();
  treeView.SelectedItemChanged += (a, b) =>
  {
    var treeViewItem = treeView.SelectedItem as TreeViewItem;
    if (treeViewItem == null) return;

    // allow multiple selection
    // when control key is pressed
    if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl))
    {
      // suppress selection change notification
      // select all selected items
      // then restore selection change notifications
      var isSelectionChangeActive = 
        IsSelectionChangeActiveProperty.GetValue(treeView, null);

      IsSelectionChangeActiveProperty.SetValue(treeView, true, null);
      selectedItems.ForEach(item => item.IsSelected = true);

      IsSelectionChangeActiveProperty.SetValue
      (
        treeView, 
        isSelectionChangeActive, 
        null
      );
    }
    else
    {
      // deselect all selected items except the current one
      selectedItems.ForEach(item => item.IsSelected = (item == treeViewItem) );
      selectedItems.Clear();
    }

    if (!selectedItems.Contains(treeViewItem))
    {
      selectedItems.Add(treeViewItem);
    }
    else
    {
      // deselect if already selected
      treeViewItem.IsSelected = false;
      selectedItems.Remove(treeViewItem);
    }
  };

}
Dr1Ku
  • 2,875
  • 3
  • 47
  • 56
Kess
  • 141
  • 1
  • 3
  • 1
    Nice! A method that works, uses the existing TreeView (i.e. doesn't rewrite it from scratch) and uses the TreeView's own IsSelected dependency propterty. Had to change TreeViewItem to the item that I had set the binding to, but that was about it. Thanks. – markmuetz Aug 04 '11 at 16:27
  • It has a few problems. One of them is that you cannot Ctrl+select and Ctrl+deselect the same item. I assume it's because no SelectedItemChanged event is triggered when clicking the same item twice. I'm looking into it. And an open question is how I can use data binding to the SelectedItem with multiple selection. – ygoe Jul 19 '12 at 14:50
  • Did you ever manage to fix the Ctrl+select and Ctrl+deselect bug? – user589195 Oct 26 '12 at 12:57
  • Well @LonelyPixel, did you fix it? – Christoffer Lette Nov 06 '12 at 09:39
  • 1
    I'm not using this code. The TreeViewEx open-source project (which I have somewhat altered but not yet published) served as a way better basis for me. It's basically a rewrite of the TreeView control with the desired features already built-in. (And the source code under your control to do further tweaks and fixes.) – ygoe Nov 06 '12 at 13:27
  • 1
    I'm confused here, which class should have this property and the method? – Pratik Dec 08 '20 at 18:09
  • Yes, where does this code go? – Daniel Möller Jun 20 '23 at 18:36
0

Depending on the exact semantics you desire, the solution may be extremely simple:

If the root of your tree is anything but a TreeView -- for example if it is a plain ItemsControl -- all TreeViewItems in the tree will be independently selectatble so you basically get mulitiselect for free. So just use an ItemsControl instead of a TreeView for the root of your tree.

This solution has the benefit of being extraordinarily simple to implement. It differs from mattdlong's solution in that:

  • His solution deselects all other items when an item is clicked, so you have to ctrl-click items to multiselect.
  • With this solution a single click will select/deselect the item you clicked on, but there is no way to quickly select an item and simultaneously deselect all others.

Another difference is that keyboard navigation (arrow keys) in his solution deselects all items, whereas in this solution keyboard navigation does not deselect items.

You should choose between these solutions based on the semantics you prefer (single click to add item vs ctrl-click to add item, etc). If you want more advanced semantics, such as Shift-Click, etc, it is relatively to add.

Note that you can also custom style TreeViewItems using a ToggleButton or CheckBox anywhere in the ItemContainerTemplate that has Checked={Binding IsSelected}. This allows the user to select items by clicking on the ToggleButton or CheckBox.

Ray Burns
  • 62,163
  • 12
  • 140
  • 141
  • 1
    I have some experience with trees in UI to learn one rule - there are so many details in implementing multiple selection correctly, that I really do not wish to take this road. I prefer someone, whose business is designing UI controls and who has already invested in testing and tuning, rather than producing something quick, which will constantly draw resources to fix and maintain. It is nice as a programming exercise, granted. – mark Jan 19 '10 at 07:36
  • 1
    I think you misunderstood my answer. What I was trying to say is that TreeViewItem supports simple multiselection out of the box, so **you don't have to write anything at all.** If you like its built-in multiselection semantics you can just use it. If you want something different than the built-in multiselect behavior, **then** you'll have to either buy a control or write code like mattdlong describes. – Ray Burns Jan 20 '10 at 21:20
  • 3
    When I try to replace a TreeView control with an ItemsControl, it all fails with a stack trace longer than a page. A style for a TreeViewItem cannot be applied to that control, or something. So how is that supposed to work? Is it still a hierarchical tree control or will it become a flat list then? (In which case it'd be useless.) – ygoe Jul 19 '12 at 14:57
  • Ya, a working example would be nice, Dude. I'm experiencing the same problem as LonelyPixel... – Riegardt Steyn Jul 23 '13 at 14:32
  • Using VS 2015, I am unable to select `TreeViewItem` children of an `ItemsControl` in a `TreeView`. – Andrew Jun 27 '18 at 17:15