问题 具有多个选择的WPF TreeView [关闭]


标准的WPF 树视图 不支持多项选择。

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


4118
2017-07-22 08:19


起源

看一下这个讨论: stackoverflow.com/questions/459375/...
在这里查看我的答案: stackoverflow.com/a/13412801/166452 - Ignacio Soler Garcia


答案:


下面的代码工作正常,更简单。但是,退回是使用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);
    }
  };

}

13
2017-07-13 16:05



太好了!一个有效的方法,使用现有的TreeView(即不从头重写它)并使用TreeView自己的IsSelected依赖属性。不得不将TreeViewItem更改为我已设置绑定的项目,但这是关于它的。谢谢。 - markmuetz
它有一些问题。其中一个是你不能按Ctrl +选择和Ctrl +取消选择相同的项目。我假设是因为两次单击同一项时没有触发SelectedItemChanged事件。我正在研究它。一个悬而未决的问题是如何使用多个选择将数据绑定到SelectedItem。 - ygoe
你有没有设法修复Ctrl +选择和Ctrl +取消选择错误? - user589195
那么@LonelyPixel,你修好了吗? - Christoffer Lette
我没有使用此代码。 TreeViewEx开源项目(我有些改动但尚未发布)为我提供了更好的基础。它基本上是TreeView控件的重写,具有已经内置的所需功能。 (以及您可以控制的源代码,以进行进一步的调整和修复。) - ygoe


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

如果树的根不是一个 TreeView  - 例如,如果它是平原 ItemsControl  - 树中的所有TreeViewItems都可以独立选择,因此您基本上可以免费获得多重选择。所以只需使用一个 ItemsControl 代替 TreeView 为你的树的根。

该解决方案具有实现异常简单的优点。它与mattdlong的解决方案不同:

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

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

您应该根据您喜欢的语义选择这些解决方案(单击以添加项目与按住Ctrl键单击以添加项目等)。如果您想要更高级的语义,例如Shift-Click等,则需要相对添加。

请注意,您还可以使用a自定义样式TreeViewItems ToggleButton 要么 CheckBox 在任何地方 ItemContainerTemplate 具有 Checked={Binding IsSelected}。这允许用户通过单击选择项目 ToggleButton 要么 CheckBox


0
2018-01-19 05:19



我在UI中有一些使用树的经验来学习一条规则 - 正确实现多项选择有很多细节,我真的不想走这条路。我更喜欢某人,他的业务是设计UI控件,并且已经投入了测试和调优,而不是生产快速的东西,这将不断地吸引资源来修复和维护。作为编程练习,这很好。 - mark
我想你误解了我的答案。我想说的是TreeViewItem支持开箱即用的简单多选,所以 你根本不需要写任何东西。  如果你喜欢它的内置多选语义,你可以使用它。如果您想要与内置多选行为不同的内容, 然后 你必须购买控件或编写像mattdlong描述的代码。 - Ray Burns
当我尝试用ItemsControl替换TreeView控件时,它都会因堆栈跟踪长于页面而失败。 TreeViewItem的样式无法应用于该控件或其他内容。那该怎么办呢?它仍然是一个分层树控件还是会成为一个平面列表? (在这种情况下它没用。) - ygoe
雅,一个工作的例子会很好,伙计。我遇到了与LonelyPixel相同的问题...... - Heliac
使用VS 2015,我无法选择 TreeViewItem 一个孩子 ItemsControl 在一个 TreeView。 - Andrew