具有多个选择的WPF TreeView

mar*_*ark 11 wpf treeview multi-select

标准WPF 树视图不支持多个选择.

如何添加支持多个选择的树视图到我的WPF应用程序?商业产品很好(我目前知道一个商业实施 - http://www.telerik.com/products/wpf/treeview.aspx)

小智 13

下面的代码工作正常,更简单.但是,退回是使用treeview类的非公共属性IsSelectionChangeActive.代码如下:

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

}
Run Code Online (Sandbox Code Playgroud)


Ray*_*rns 0

根据您想要的确切语义,解决方案可能非常简单:

如果你的树的根不是一个TreeView——例如,如果它是一个普通的ItemsControl——树中的所有 TreeViewItems 都将是独立选择的,所以你基本上可以免费获得多重选择。因此,只需使用 anItemsControl而不是 aTreeView作为树的根。

该解决方案的优点是实施起来非常简单。它与 mattdlong 的解决方案的不同之处在于:

  • 他的解决方案会在单击某个项目时取消选择所有其他项目,因此您必须按住 Ctrl 键单击项目才能进行多选。
  • 使用此解决方案,单击一次即可选择/取消选择您单击的项目,但无法快速选择一个项目并同时取消选择所有其他项目。

另一个区别是,他的解决方案中的键盘导航(箭头键)取消选择所有项目,而在此解决方案中键盘导航不会取消选择项目。

您应该根据您喜欢的语义在这些解决方案之间进行选择(单击添加项目与按住 Ctrl 单击添加项目等)。如果你想要更高级的语义,比如Shift-Click等,相对来说是要添加的。

请注意,您还可以使用ToggleButtonCheckBoxItemContainerTemplate具有 的任何位置自定义 TreeViewItems 的样式Checked={Binding IsSelected}。这允许用户通过单击ToggleButton或来选择项目CheckBox

  • 当我尝试用 ItemsControl 替换 TreeView 控件时,一切都失败,堆栈跟踪长于页面。TreeViewItem 的样式不能应用于该控件或其他控件。那么这应该如何运作呢?它仍然是一个分层树控件还是会变成一个平面列表?(在这种情况下,它就没用了。) (3认同)