【问题标题】:Handled TreeView.SelectedItemChanged event still bubbles处理的 TreeView.SelectedItemChanged 事件仍然冒泡
【发布时间】:2011-09-01 08:00:56
【问题描述】:

我有一个 TreeView 通过HierarchicalDataTemplates 绑定到由几个不同类组成的层次结构。当树中的一个项目被选中时,SelectedItemChanged 事件当然会愉快地通过父项目向上冒泡,这是应该的。在我将e.Handled 设置为true 之后,它应该 做但仍然会做的事情是愉快地继续冒泡。

该事件仍将在父项上触发,RoutedPropertyChangedEventArgs 看起来与被选中的父项完全相同;甚至OriginalSource 属性也将指向父项,而不是最初选择的项。 e.Handled 当然是false

here 提出了几乎相同的问题,但我没有使用 EventAggregator 或 CAL,而找到的解决方法 here 并没有太大帮助,因为我不是专门针对鼠标事件。

有没有什么方法可以精确地获取实际选择的项目或强制停止冒泡的疯狂(而不使用我能想到的使用全局变量的非常暴力和不道德的破解)?

感谢您提供任何见解。

【问题讨论】:

  • 你不能只看被处理的属性更上链而不做任何事情吗?
  • 什么意思?问题是在事件处理程序中,我不知道该事件的“实例”是直接由 UI 中的实际选择产生的初始事件,还是由于冒泡而被触发且可以忽略的事件。
  • 我想我现在明白了;你的意思是e.Handled?那是我尝试使用的第一件事,但是输入处理程序时始终是false,无论我之前是否将其设置为true
  • 无赖,我以为 e.Handled 应该被传递。
  • 我的看法是,它的目的是告诉框架停止冒泡当前事件 - “我得到了这个,去做其他事情。”

标签: .net wpf com treeview event-bubbling


【解决方案1】:

在阅读了 Rick 的回答后,我与一位同事交谈,结果发现他之前也遇到过同样的问题。我在我的应用程序中尝试了各种事情(发现:TreeViewItem.Selected 事件的行为方式完全相同)和一个测试项目,发现在测试应用程序中,事件的触发完全符合人们的预期。因此,导致这种行为差异的环境必须存在显着差异(XAML 和 ViewModel 类几乎相同)——罪魁祸首似乎是 COM,它在 COM 应用程序中精确托管 WPF 控件。

我同事的应用程序是使用 VSTO 的 Word 扩展,而我的应用程序是用于 Visual Studio 2010 的 VSPackage - Word 和 VS2010 在大多数情况下仍然是本机代码。另一方面,我的测试应用程序当然是一个小型的普通 WPF 项目。我向其中添加了一个带有 ElementHost 的 WinForms 表单,该表单又托管了一个带有 TreeView 的 UserControl,但它仍然可以正常工作,所以在我看来,主机 COM 应用程序确实以某种方式干扰了在TreeView 和 TreeViewItems。

幸运的是,我的同事找到/搜索了一个暂时可行的解决方案 - 在您完成对事件的实际反应后,在事件处理程序方法结束时,再次将 TreeViewItem 设置为选中并聚焦它:

item.Focus();
item.IsSelected = true;

我们不明白为什么,但这将阻止项目被错误地重新选择(这显然不是 WPF 意义上的真正冒泡事件)。

再次感谢 Rick 推动我将 TreeView 和 TreeViewItem 事件分开。

【讨论】:

    【解决方案2】:

    您的问题让我感到困惑,因为 SelectedItemChanged 事件是 TreeView 事件,而不是 TreeViewItem 事件。 “嘿伙计,我的活动远不及你的活动!”

    当所选项目发生变化时,TreeView 会在自身TreeView如果未处理上引发SelectedItemChanged 事件,它开始向页面的根元素。

    当您需要证明时,编写一个小型测试程序会有所帮助。

    这是一个包含在Grid 中的小TreeView

    <Grid TreeView.SelectedItemChanged="Grid_SelectedItemChanged">
        <TreeView SelectedItemChanged="TreeView_SelectedItemChanged">
            <TreeViewItem TreeView.SelectedItemChanged="TreeViewItem_SelectedItemChanged" Header="Item1">
                <TreeViewItem TreeView.SelectedItemChanged="TreeViewItem_SelectedItemChanged" Header="Item2">
                    <TreeViewItem TreeView.SelectedItemChanged="TreeViewItem_SelectedItemChanged" Header="Item3"/>
                </TreeViewItem>
            </TreeViewItem>
        </TreeView>
    </Grid>
    

    这是测试的代码隐藏:

    private void Grid_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
    {
        SelectedItemChanged(sender, e, "Grid");
    }
    
    private void TreeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
    {
        SelectedItemChanged(sender, e, "TreeView");
        e.Handled = true;
    }
    
    private void TreeViewItem_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
    {
        SelectedItemChanged(sender, e, "TreeViewItem");
    }
    
    private void SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e, string handler)
    {
        Debug.WriteLine("");
        Debug.WriteLine(string.Format("SelectedItemChanged: handler = {0}", handler));
        Debug.WriteLine(string.Format("e.NewValue.Header = {0}", (e.NewValue as TreeViewItem).Header));
        Debug.WriteLine(string.Format("sender = {0}", sender));
        Debug.WriteLine(string.Format("e.Source = {0}", e.Source));
        Debug.WriteLine(string.Format("e.OriginalSource = {0}", e.OriginalSource));
    }
    

    运行它并单击第一项会产生以下调试输出:

    SelectedItemChanged: handler = TreeView
    e.NewValue.Header = Item1
    sender = System.Windows.Controls.TreeView Items.Count:1
    e.Source = System.Windows.Controls.TreeView Items.Count:1
    e.OriginalSource = System.Windows.Controls.TreeView Items.Count:1
    

    这表明事件是在 TreeView 本身上引发的,并且将 e.Handled 设置为 true 会阻止 Grid 接收事件。注释掉该行,它会冒泡到Grid

    但在任何情况下,TreeViewItem 都不会调用 SelectedItemChanged 处理程序。

    当事情没有按照您认为的那样运行时,请尝试使用小型测试程序。做实验并找到问题的核心要容易得多!

    【讨论】:

    • 谢谢。虽然这并不能真正解决问题,但明确提到 TreeView 和 TreeViewItems 上引发的事件之间的差异,我确实忽略了这一点,让我走错了路。真正的原因显然是完全不同的东西,并且似乎与最终托管在 COM 应用程序中的控件有关 - 至少这是我所能掌握的所有信息。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多