English 中文(简体)
当单击某个空区域时,如何取消选择 WPF 树形视图中的所有已选项目?
原标题:
  • 时间:2009-01-29 10:12:53
  •  标签:

我在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">
问题回答

我发现这对我来说工作得更好。我检查原始来源,如果它来自TreeViewItem,将是图像或TextBlock。我还使用具有分层数据模板的视图对象,并且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;
            }
        }
    }

选择不可用的问题可以通过在设置TreeViewItem.IsSelected后调用TreeView的Focus方法来解决。

可能还有两个问题:

  1. The treeview is binded so the SelectedItem is an item of the binded collection.
  2. There is many levels so ItemContainerGenerator do not contain deepest level objects

出于这些原因,我使用此功能,但选择不得触发任何事件。

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

我曾经实现了一种通用选择控件,需要这种行为。

这就是我的方法看起来的样子(为treeview适配)。

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

使用下面的扩展类

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

希望它对你有用。我是这样运作的……

在尝试自定义树列表视图实现时,我自己也遇到了这种情况。寻找了很长时间后,我终于找到了适合我的解决方案。

完整的解释可以在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 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;
}

如果没有点击任何 TreeViewItem,则将取消选择当前选定的 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;                    
        }
    }
}

希望这是您寻找的!

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

对于 C# 的 TreeView,你可以使用 treeview.SelectedNode = null; 我不确定这是否适用于 WPF。





相关问题
热门标签