如何在单击某个空白区域时取消选择WPF树视图中的所有选定项目?

时间:2009-01-29 10:12:53

标签: wpf

我对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 1}}。如果我向我的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">

9 个答案:

答案 0 :(得分:6)

我发现这对我来说效果更好。我查看原始资源,如果它来自treeviewitem,它将是一个图像或文本块。我还使用带有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;
            }
        }
    }

答案 1 :(得分:5)

在设置TreeViewItem.IsSelected后,可以通过调用FocusView在TreeView上解决不可选择的问题。

答案 2 :(得分:4)

还有两个问题:

  1. 树视图已绑定,因此SelectedItem是绑定集合的项目。
  2. 有很多级别,因此ItemContainerGenerator不包含最深层次的对象
  3. 由于这个原因,我使用了这个功能,但选择不得触发任何事件。

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

答案 3 :(得分:2)

我实施了一次通用选择控制,并且需要这种行为。

这是我的方法看起来(适用于树视图):

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,则用户单击空白区域。

答案 4 :(得分:2)

使用下面的扩展类

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

然后在Treeview的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();
    }

希望它适合你。我让它以这种方式工作......

答案 5 :(得分:1)

在我找到一个对我有用的解决方案很久以后,我自己使用自定义的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事件并将事件源保存到TreeView上的Tag属性中。然后,当您需要清除它时,可以访问控件上的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;
}

答案 6 :(得分:0)

如果没有单击,则取消选择当前选择的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;                    
        }
    }
}

希望这就是你要找的东西!

答案 7 :(得分:0)

对于C#树视图,您使用treeview.SelectedNode = null;我不确定这是否适用于WPF。

答案 8 :(得分:0)

MVVM:在事件处理程序控件中/单击鼠标左键时调用此方法:

private void SetTreeViewSelection(object sender, MouseButtonEventArgs mouseButtonEventArgs)
{
  var treeView = (TreeView)sender;
  if (treeView.SelectedItem == null)
  {
    return;
  }
  
  IInputElement dropNode = treeView.InputHitTest(mouseButtonEventArgs.GetPosition(treeView));
  if (dropNode is ScrollViewer)
  {
    var myBindableObject = (MyBindableObject)treeView.SelectedItem;
    myBindableObject.IsSelected = false;
  }
}