Как отменить выбор всех выбранных элементов в древовидном представлении WPF при нажатии на пустую область? - PullRequest
9 голосов
/ 29 января 2009

У меня довольно забавная проблема с WPF. У меня есть древовидное представление, и пока выбор элементов работает нормально. Проблема в том, что я хочу отменить выбор текущего выбранного элемента, когда пользователь щелкает внутри пустой области древовидной структуры. По умолчанию древовидная структура сохраняет выбранный текущий элемент, и я добавил опцию контекстного меню, чтобы отменить ее выбор, что довольно сложно:

// Note: This is done recursivly from the start, so it
// works for child items as well
treeView.ItemContainerGenerator.ContainerFromItem(treeView.SelectedItem) as TreeViewItem).IsSelected = false;

Более того, это нелогично, так как от пользователя требуется сначала щелкнуть правой кнопкой мыши, а затем, после отмены выбора таким способом, пользователь больше не может выбирать его, щелкая элемент. Как это должно работать?

Редактировать: Еще немного информации: я добавил обработчик в TreeView для обработки событий щелчка мыши, но отправитель всегда является экземпляром TreeView, даже если я щелкаю непосредственно по TreeViewItem. Если вместо этого я добавлю обработчик к своему TreeView.ItemTemplate (то есть к первому дочернему элементу в шаблоне), я никогда не получу события, когда нажимаю на пустую область (что довольно логично). Код выглядит так:

    private void MyTreeView_MouseUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
    {
        if ((sender as TreeViewItem) == null)
        {
            // Always triggered
            System.Diagnostics.Trace.Write("Empty area clicked");
        }
    } 

И XAML для этого:

<TreeView x:Name="MyTreeView" Margin="3" MouseUp="MyTreeView_MouseUp">

Ответы [ 8 ]

6 голосов
/ 15 июля 2009

Я нашел, что это работает намного лучше для меня. Я проверяю источник оригинала, который для меня, если он придет из дерева, будет изображением или текстовым блоком. Я также использую объект представления с HierarchicalDataTemplate, а BasicTreeViewBase является базовым классом для всех моих различных объектов. Вот код.

private void TemplateTreeView_MouseDown(object sender, MouseButtonEventArgs e)
    {
        if (e.ChangedButton == MouseButton.Right && !(e.OriginalSource is Image) && !(e.OriginalSource is TextBlock))
        {
            BasicTreeViewBase item = TemplateTreeView.SelectedItem as BasicTreeViewBase;
            if (item != null)
            {
                TemplateTreeView.Focus();
                item.IsSelected = false;
            }
        }
    }
5 голосов
/ 30 января 2009

Невыбираемая проблема может быть решена с помощью вызова Focus на TreeView после установки TreeViewItem.IsSelected.

4 голосов
/ 06 июня 2011

Может быть еще две проблемы:

  1. Древовидное представление связано, поэтому SelectedItem является элементом связанной коллекции.
  2. Существует много уровней, поэтому ItemContainerGenerator не содержит объектов самого глубокого уровня

по этой причине я использую эту функцию, но выбор не должен запускать какие-либо события.

private void UnselectTreeViewItem(TreeView pTreeView)
{ 
  if(pTreeView.SelectedItem == null)
    return;

  if(pTreeView.SelectedItem is TreeViewItem)
  {
    (pTreeView.SelectedItem as TreeViewItem).IsSelected = false;
  }
  else
  {
    TreeViewItem item = pTreeView.ItemContainerGenerator.ContainerFromIndex(0) as TreeViewItem;
    if (item != null)
    {
      item.IsSelected = true;
      item.IsSelected = false;
    }
  }
}
2 голосов
/ 16 сентября 2011

Используйте класс расширения ниже

public static class TreeViewExtensions
{
    public static TreeViewItem ContainerFromItem(this TreeView treeView, object item)
    {
        TreeViewItem containerThatMightContainItem = (TreeViewItem)treeView.ItemContainerGenerator.ContainerFromItem(item);
        if (containerThatMightContainItem != null)
            return containerThatMightContainItem;
        else
            return ContainerFromItem(treeView.ItemContainerGenerator, treeView.Items, item);
    }

    private static TreeViewItem ContainerFromItem(ItemContainerGenerator parentItemContainerGenerator, ItemCollection itemCollection, object item)
    {
        foreach (object curChildItem in itemCollection)
        {
            TreeViewItem parentContainer = (TreeViewItem)parentItemContainerGenerator.ContainerFromItem(curChildItem);
            TreeViewItem containerThatMightContainItem = (TreeViewItem)parentContainer.ItemContainerGenerator.ContainerFromItem(item);
            if (containerThatMightContainItem != null)
                return containerThatMightContainItem;

            TreeViewItem recursionResult = ContainerFromItem(parentContainer.ItemContainerGenerator, parentContainer.Items, item);
            if (recursionResult != null)
                return recursionResult;
        }
        return null;
    }
}

Затем в событии MouseDown дерева используйте метод расширения, как показано ниже:

    private void trview_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
    {
        if ((sender as TreeViewItem) == null)
        {
            if (this.trview.ContainerFromItem(trview.SelectedItem) != null)
            {
                this.trview.ContainerFromItem(trview.SelectedItem).IsSelected = false;
            }
        }
        this.trview.Focus();
    }

Надеюсь, это работает для вас. У меня так работает ...

2 голосов
/ 15 июля 2009

Я реализовал общий элемент управления выбором один раз и потребовал такого поведения.

Вот так выглядел мой метод (адаптированный для дерева):

protected override void OnMouseUp(MouseButtonEventArgs e)
{
    base.OnMouseUp(e);

    DependencyObject dpSource = e.OriginalSource as DependencyObject;

    if (dpSource.FindVisualAncestor(o => typeof(TreeViewItem).IsAssignableFrom(o.GetType())) == null)
            UnselectAll();
}

По сути, поднимитесь по дереву от источника. Если TreeViewItem не был найден, пользователь щелкнул пустое место.

1 голос
/ 12 сентября 2013

Я сам сталкивался с этой ситуацией с помощью собственной реализации Tree List View, после долгого поиска я наконец нашел решение, которое работало для меня.

Полное объяснение можно найти на http://social.msdn.microsoft.com/Forums/vstudio/en-US/36aca7f7-0b47-488b-8e16-840b86addfa3/getting-treeviewitem-for-the-selected-item-in-a-treeview

Основная идея заключается в том, что вы фиксируете событие TreeViewItem.Selected и сохраняете источник события в атрибуте Tag в TreeView. Затем, когда вам нужно очистить его, вы можете получить доступ к атрибуту Tag на вашем элементе управления и установить значение IsSelected в False. Это работает для меня с 2 уровнями вложенных детей. Надеюсь, это сработает для вас.

Ради настойчивости:

Объявление TreeView

  <TreeView Name="myTreeView" TreeViewItem.Selected="OnItemSelected"
    ItemsSource="{Binding Source={StaticResource myHierarchicalData}}"/>

Обработчик событий

private void OnItemSelected(object sender, RoutedEventArgs e)
{
    myTreeView.Tag = e.OriginalSource;
}

Очистить логику выбора

if (myTreeView.SelectedItem != null)
{
    TreeViewItem selectedTVI = myTreeView.Tag as TreeViewItem;
    // add your code here mine was selectedTVI.IsSelected = false;
}
0 голосов
/ 27 мая 2015

Для вида дерева C # вы используете treeview.SelectedNode = null; Я не уверен, что это работает для WPF.

0 голосов
/ 30 января 2009

Это отменяет выбор текущего выбранного TreeViewItem, если ни один из них не был нажат:

private void MyTreeView_PreviewMouseDown(object sender, MouseButtonEventArgs e) {
    if ((sender as TreeViewItem) == null) {
        TreeViewItem item = MyTreeView.SelectedItem as TreeViewItem;
        if(item != null){
            item.IsSelected = false;                    
        }
    }
}

Надеюсь, это то, что вы искали!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...