C# 事件冒泡和RoutedEventArgs源属性
我试图在一个简单的WPF应用程序中理解RoutedEventArgs.Source属性。这是XAML代码C# 事件冒泡和RoutedEventArgs源属性,c#,wpf,xaml,events,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
<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;
}
}
}
使用系统;
使用System.Collections.ObjectModel;
使用System.Windows;
名称空间BubbleDemo
{
公共部分类主窗口:窗口
{
私有ObservableCollection消息=新ObservableCollection();
公共主窗口()
{
初始化组件();
this.DataContext=消息;
}
私有void AddMessage(字符串消息、对象发送方、路由目标)
{
messages.Add(String.Format(“{0},发送方:{1};源:{2};原始源:{3}”),
消息(发件人作为FrameworkElement)。名称,
(e.Source作为FrameworkElement)。名称,
(e.OriginalSource作为FrameworkElement).Name);
}
专用无效OnOuterButtonClick(对象发送方,路由目标)
{
AddMessage(“外部事件”,发送方,e);
}
私有void OnInner1(对象发送方,RoutedEventArgs e)
{
AddMessage(“inner1”,发送者,e);
}
Inner2上的私有void(对象发送方,RoutedEventArgs e)
{
AddMessage(“inner2”,发送者,e);
e、 已处理=正确;
}
私有void OnButton2(对象发送方,路由目标e)
{
添加消息(“按钮2”,发送者,e);
e、 来源=发送方;
}
}
}
当我单击InnerButton1时,将引发click事件,然后由OnInner1处理程序执行。
之后,执行OnButton2处理程序,该处理程序使用sender参数设置RoutedEventArgs.Source属性。
如果构建并执行此代码,则可以看到输出结果。
当事件到达OnOuterButtonClick处理程序时,底部列表框中的输出应为:
inner1,发送方:innerButton1;资料来源:innerButton1;原始来源:innerButton1按钮2,发送方:按钮2;资料来源:innerButton1;原始来源:innerButton1
外部事件,发送方:stackPanel1;来源:按钮2;原始来源:innerButton1
但结果是这样的 inner1,发送方:innerButton1;资料来源:innerButton1;原始来源:innerButton1
按钮2,发送方:按钮2;资料来源:innerButton1;原始来源:innerButton1
外部事件,发送方:stackPanel1;来源:innerButton1;原始来源:innerButton1
OnButton2处理程序中重新分配的RoutedEventTargets.Source属性已更改,但返回到OnOutButtonClick处理程序中的innerButton1引用 为什么会发生这种情况?
谢谢这是一个非常好的问题,我必须研究一下.net的源代码,找出它为什么是这样的:
public object Source
{
get {return _source;}
set
{
if (UserInitiated && InvokingHandler)
throw new InvalidOperationException(SR.Get(SRID.RoutedEventCannotChangeWhileRouting));
...
}
}
源属性如下所示:
public object Source
{
get {return _source;}
set
{
if (UserInitiated && InvokingHandler)
throw new InvalidOperationException(SR.Get(SRID.RoutedEventCannotChangeWhileRouting));
...
}
}
当事件冒泡或隧道时,每当用户试图设置源时,就会抛出此执行选项
我假设.net Framework中负责此行为的部分也捕获了异常,因此您没有意识到问题。事实上,当试图设置源属性时,当事件冒泡时,调试器显示,即未在设置后立即更改
不幸的是,源代码仅显示事件冒泡(或隧道)时,Microsoft不允许更改源属性,但不允许为什么
如果出于任何原因,您需要获取有关处理事件的Previor处理程序的信息,您可以创建自己的RoutedEventArgs
扩展,并添加另一个包含此信息的属性
最后,您可以扩展
按钮
类,并引发您自己的事件,其中包含相应的路由EventTargetSwithHandlerHistory
对象:)这是一个有趣的问题,需要反映.net路由
引擎。因此,我发现每个UIElement
都使用RaiseEvent()
方法来启动RoutedEvent
。执行此操作时,它首先构建EventRoute
。在构建EventRoute
时,它根据RoutingStrategy
创建调用处理程序列表,即Bubble
和Tunnel
它在UIElement
所属的VisualTree
上下移动,并找出有多少处理程序附加到给定的RoutedEvent
。显然,对于innerButton1
和innerButton1
有三个处理程序
现在UIElement
为其RoutedEvent
获取了EventRoute
,接下来它在EventRoute
上调用InvokeHandlers()
。在调用循环中的处理程序时,InvokeHandler
将args.Source
重置为原始值,如下所示,它为冒泡策略执行此操作
for (int index = 0; index < this._routeItemList.Count; ++index)
{
if (index >= endIndex)
{
object bubbleSource = this.GetBubbleSource(index, out endIndex);
if (!reRaised)
args.Source = bubbleSource ?? source;
}
for(int index=0;index=endIndex)
{
object bubbleSource=this.GetBubbleSource(index,out-endIndex);
如果(!重新评级)
args.Source=泡泡源??源;
}
因此,在每次处理程序调用之前,源
将重置为其原始值,因此在任何处理程序中对其进行更改都不会传递给下一个处理程序。相关: