WPF TreeView with Multiple Selection [closed]

这一生的挚爱 提交于 2019-11-28 20:49:15
Kess

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

}

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.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!