c# - 事件冒泡和 RoutedEventArgs Source 属性

标签 c# wpf xaml events

我试图理解简单 WPF 应用程序中的 RoutedEventArgs.Source 属性。这是 XAML 代码

    <Window x:Class="BubbleDemo.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <StackPanel x:Name="stackPanel1" Button.Click="OnOuterButtonClick">
        <Button x:Name="button1" Content="Button 1" Margin="5" />
        <Button x:Name="button2" Margin="5" Click="OnButton2">
            <ListBox x:Name="listBox1">
                <Button x:Name="innerButton1" Content="Inner Button 1" Margin="4" Padding="4" Click="OnInner1" />
                <Button x:Name="innerButton2" Content="Inner Button 2" Margin="4" Padding="4" Click="OnInner2" />
            </ListBox>
        </Button>
        <ListBox ItemsSource="{Binding}" />        
    </StackPanel>
</Window>

这是背后的代码

using System;
using System.Collections.ObjectModel;
using System.Windows;

namespace BubbleDemo
{
    public partial class MainWindow : Window
    {
        private ObservableCollection<string> messages = new ObservableCollection<string>();
        public MainWindow()
        {
            InitializeComponent();
            this.DataContext = messages;
        }

        private void AddMessage(string message, object sender, RoutedEventArgs e)
        {
            messages.Add(String.Format("{0}, sender: {1}; source: {2}; original source: {3}",
                message, (sender as FrameworkElement).Name,
                (e.Source as FrameworkElement).Name,
                (e.OriginalSource as FrameworkElement).Name));  
        }

        private void OnOuterButtonClick(object sender, RoutedEventArgs e)
        {
            AddMessage("outer event", sender, e);   
        }

        private void OnInner1(object sender, RoutedEventArgs e)
        {
            AddMessage("inner1", sender, e);
        }

        private void OnInner2(object sender, RoutedEventArgs e)
        {
            AddMessage("inner2", sender, e);

            e.Handled = true;
        }

        private void OnButton2(object sender, RoutedEventArgs e)
        {
            AddMessage("button2", sender, e);
            e.Source = sender;
        }
    }
}

当我单击 InnerButton1 时,会引发单击事件,然后执行 OnInner1 处理程序。 之后执行 OnButton2 处理程序,该处理程序使用 sender 参数设置 RoutedEventArgs.Source 属性。 如果构建并执行此代码,您可以看到输出结果。 当事件到达 OnOuterButtonClick 处理程序时,底部 ListBox 中的输出应为:

inner1,发件人:innerButton1;来源:innerButton1;原始来源:innerButton1
按钮2,发送者:按钮2;来源:innerButton1;原始来源:innerButton1
外部事件,发送者:stackPanel1;来源:button2;原始来源:innerButton1

但输出是这样的

inner1,发件人:innerButton1;来源:innerButton1;原始来源:innerButton1
按钮2,发送者:按钮2;来源:innerButton1;原始来源:innerButton1
外部事件,发送者:stackPanel1;来源:innerButton1;原始来源:innerButton1

在 OnButton2 处理程序中重新分配的 RoutedEventArgs.Source 属性已更改,但返回到 OnOuterButtonClick 处理程序中的引用 innerButton1。

为什么会发生这种情况? 谢谢

最佳答案

这是一个非常好的问题,我必须研究 .net 的来源来找出为什么它是这样的:

Source 属性如下所示:

public object Source
{
  get {return _source;}
  set
  {
    if (UserInitiated && InvokingHandler)
      throw new InvalidOperationException(SR.Get(SRID.RoutedEventCannotChangeWhileRouting));

    ...
  }
}

当事件处于冒泡或隧道状态时,每当用户尝试设置源时,都会引发此异常。

我假设 .net Framework 负责处理此行为的部分也会捕获异常,因此您不会意识到该问题。事实上,当尝试设置源属性时,当事件冒泡时,调试器会显示设置后立即更改。

不幸的是,源代码仅显示微软不允许在事件冒泡(或隧道)时更改源属性,但没有显示原因。 p>

如果您 - 无论出于何种原因 - 需要获取有关处理事件的 Prior 处理程序的信息,您可以创建自己的 RoatedEventArgs 扩展并添加另一个属性,包含此信息。

最后,您可以扩展 button 类,并引发您自己的事件,其中包含适当的 RoulatedEventArgsWithHandlerHistory 对象:)

关于c# - 事件冒泡和 RoutedEventArgs Source 属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19498162/

相关文章:

c# - 具有推断泛型参数的泛型方法

c# - C#中的布局管理器

c# - MVVM 模式和半全局数据

c# - Windows 中的自动完成文本框和 "Hide Pointer While Typing"

c# - 如何在边框后绑定(bind)我的文本?

c# - 从文件夹中拖放文件 c# wpf

c# - 在 C# 中读取自定义配置部分的键值

c# - 使用枚举是列出不同 "Types of Car"的最佳方式吗

c# - 使用 XAML/WPF 的路径/矢量的(自动)动画

c# - 自定义系统托盘 Windows Phone 8?