WPF TreeView с множественным выбором

Стандартное древовидное представление WPF не поддерживает несколько выбор.

Как добавить в приложение WPF древовидное представление, поддерживающее множественный выбор? С коммерческими продуктами все в порядке (в настоящее время мне известно об одной коммерческой реализации - http://www.telerik.com/products/wpf/treeview.aspx).


person mark    schedule 22.07.2009    source источник
comment
Взгляните на это обсуждение: stackoverflow.com/questions/459375/   -  person    schedule 15.02.2012
comment
Проверьте мой ответ здесь: stackoverflow.com/a/13412801/166452   -  person Ignacio Soler Garcia    schedule 16.11.2012


Ответы (2)


Приведенный ниже код работает нормально и намного проще. Однако недостатком является использование закрытого свойства IsSelectionChangeActive класса treeview. Код ниже:

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

}
person Kess    schedule 13.07.2011
comment
Хороший! Метод, который работает, использует существующий TreeView (т. Е. Не переписывает его с нуля) и использует свойство зависимостей IsSelected TreeView. Пришлось изменить TreeViewItem на элемент, для которого я установил привязку, но это было все. Спасибо. - person markmuetz; 04.08.2011
comment
Есть несколько проблем. Одна из них заключается в том, что вы не можете Ctrl + выбрать и Ctrl + отменить выбор одного и того же элемента. Я предполагаю, что это потому, что событие SelectedItemChanged не запускается при двойном щелчке по одному и тому же элементу. Я изучаю это. И открытый вопрос, как я могу использовать привязку данных к SelectedItem с множественным выбором. - person ygoe; 19.07.2012
comment
Удалось ли вам когда-нибудь исправить ошибку Ctrl + select и Ctrl + deselect? - person user589195; 26.10.2012
comment
Ну @LonelyPixel, ты поправил? - person Christoffer Lette; 06.11.2012
comment
Я не использую этот код. Проект с открытым исходным кодом TreeViewEx (который я несколько изменил, но еще не опубликовал) послужил для меня лучшей основой. По сути, это переписывание элемента управления TreeView с уже встроенными желаемыми функциями. (И исходный код под вашим контролем для дальнейших настроек и исправлений.) - person ygoe; 06.11.2012
comment
Я запутался, у какого класса должно быть это свойство и метод? - person Pratik; 08.12.2020

В зависимости от желаемой семантики решение может быть очень простым:

Если корень вашего дерева не является TreeView - например, если это простой ItemsControl - все элементы TreeViewItems в дереве будут независимо выбираться, так что вы в основном получаете mulitiselect бесплатно. Так что просто используйте ItemsControl вместо TreeView для корня вашего дерева.

Преимущество этого решения состоит в том, что его очень просто реализовать. Он отличается от решения mattdlong тем, что:

  • Его решение отменяет выбор всех других элементов при щелчке по элементу, поэтому вам нужно щелкнуть элементы, удерживая Ctrl, для множественного выбора.
  • В этом решении одним щелчком мыши можно выбрать / отменить выбор элемента, на котором вы щелкнули, но нет возможности быстро выбрать элемент и одновременно отменить выбор всех остальных.

Другое отличие состоит в том, что навигация с помощью клавиатуры (клавиши со стрелками) в его решении отменяет выбор всех элементов, тогда как в этом решении навигация с помощью клавиатуры не отменяет выбор элементов.

Вы должны выбирать между этими решениями на основе предпочтительной семантики (один щелчок, чтобы добавить элемент, или Ctrl + щелчок, чтобы добавить элемент, и т. Д.). Если вам нужна более продвинутая семантика, такая как Shift-Click и т. Д., Это относительно добавить.

Обратите внимание, что вы также можете настроить стиль TreeViewItems, используя ToggleButton или CheckBox в любом месте ItemContainerTemplate, имеющего Checked={Binding IsSelected}. Это позволяет пользователю выбирать элементы, нажимая ToggleButton или CheckBox.

person Ray Burns    schedule 19.01.2010
comment
У меня есть некоторый опыт работы с деревьями в пользовательском интерфейсе, чтобы выучить одно правило - в правильной реализации множественного выбора так много деталей, что я действительно не хочу идти по этому пути. Я предпочитаю кого-то, чей бизнес проектирует элементы управления пользовательского интерфейса и кто уже вложил средства в тестирование и настройку, а не производить что-то быстрое, что постоянно требует ресурсов для исправления и обслуживания. Конечно, это приятно в качестве упражнения по программированию. - person mark; 19.01.2010
comment
Думаю, вы неправильно поняли мой ответ. Я пытался сказать, что TreeViewItem поддерживает простой множественный выбор из коробки, поэтому вам вообще не нужно ничего писать. Если вам нравится его встроенная семантика множественного выбора, вы можете просто использовать его . Если вы хотите чего-то отличного от встроенного поведения множественного выбора, тогда вам придется либо купить элемент управления, либо написать код, как описывает mattdlong. - person Ray Burns; 21.01.2010
comment
Когда я пытаюсь заменить элемент управления TreeView на ItemsControl, все не получается, и трассировка стека длиннее страницы. Стиль для TreeViewItem нельзя применить к этому элементу управления или чему-то еще. Так как же это должно работать? Будет ли это по-прежнему иерархическим древовидным элементом управления или тогда он станет плоским списком? (В этом случае это было бы бесполезно.) - person ygoe; 19.07.2012
comment
Да, хороший пример, чувак. У меня та же проблема, что и у LonelyPixel ... - person Riegardt Steyn; 23.07.2013
comment
Используя VS 2015, я не могу выбрать TreeViewItem потомков ItemsControl в TreeView. - person Andrew; 27.06.2018