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

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

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

Ответ 1

Код ниже работает отлично и намного проще. Однако обратная связь - это использование не общедоступного свойства 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);
    }
  };

}

Ответ 2

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

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

Это решение может быть чрезвычайно простым в реализации. Он отличается от решения mattdlong тем, что:

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

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

Вам следует выбирать между этими решениями на основе семантики, которую вы предпочитаете (один клик для добавления элемента vs ctrl-click для добавления элемента и т.д.). Если вам нужна более совершенная семантика, такая как Shift-Click и т.д., Ее можно добавить.

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