【问题标题】:WPF TreeView with Multiple Selection [closed]具有多项选择的 WPF TreeView [关闭]
【发布时间】:2010-11-12 22:09:53
【问题描述】:

标准的 WPF tree view 不支持多选。

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

【问题讨论】:

标签: wpf treeview multi-select


【解决方案1】:

下面的代码运行良好并且简单得多。然而,缺点是树视图类的非公共属性 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);
    }
  };

}

【讨论】:

  • 不错!一种有效的方法,使用现有的 TreeView(即不从头开始重写它)并使用 TreeView 自己的 IsSelected 依赖项属性。必须将 TreeViewItem 更改为我设置绑定的项目,但仅此而已。谢谢。
  • 它有一些问题。其中之一是您不能 Ctrl+select 和 Ctrl+deselect 相同的项目。我认为这是因为两次单击同一项目时没有触发 SelectedItemChanged 事件。我正在调查它。还有一个悬而未决的问题是如何使用数据绑定到 SelectedItem 进行多选。
  • 你有没有修复过 Ctrl+select 和 Ctrl+deselect 的错误?
  • 好吧@LonelyPixel,你修好了吗?
  • 我没有使用这个代码。 TreeViewEx 开源项目(我已经进行了一些修改但尚未发布)为我提供了更好的基础。它基本上是对已内置所需功能的 TreeView 控件的重写。 (以及在您的控制下进行进一步调整和修复的源代码。)
【解决方案2】:

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

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

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

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

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

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

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

【讨论】:

  • 我对 UI 中的树有一些经验来学习一个规则——正确实现多选的细节太多了,我真的不想走这条路。我更喜欢这样的人,他的业务是设计 UI 控件并且已经投资于测试和调整,而不是快速生产一些东西,这将不断地吸引资源来修复和维护。这是一个很好的编程练习,当然。
  • 我想你误解了我的回答。我想说的是 TreeViewItem 支持开箱即用的简单多选,因此您根本不需要编写任何内容。如果您喜欢它的内置多选语义,您可以使用它.如果您想要不同于内置多选行为的东西,那么您将不得不购买控件或编写 mattdlong 描述的代码。
  • 当我尝试用 ItemsControl 替换 TreeView 控件时,一切都失败了,堆栈跟踪比页面长。 TreeViewItem 的样式不能应用于该控件或其他东西。那么这应该如何工作呢?它仍然是一个层次树控件还是会变成一个平面列表? (这种情况下就没用了。)
  • 是的,一个可行的例子会很好,伙计。我遇到了和 LonelyPixel 一样的问题...
  • 使用 VS 2015,我无法在 TreeView 中选择 TreeViewItem 的子代 ItemsControl
猜你喜欢
  • 1970-01-01
  • 2010-11-05
  • 1970-01-01
  • 2021-10-02
  • 1970-01-01
  • 1970-01-01
  • 2013-09-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多