所有的UIElement 实例及其子类的实例都有一个AddHandler 方法。通过该方法可以为指定的路由事件添加处理函数,并将该处理程序添加到当前元素的处理程序集合中。
AddHandler 方法有一个AddHandler(RoutedEvent, Delegate, Boolean) 的重载。
第一个参数表示指定的路由事件;
第二个参数指定事件的处理函数;
第三个参数表明是否在事件被标记为已处理的情况(e.Handled=true)下还继续处理该事件。
WPF中,事件是根据冒泡向上路由传递的,如果我们不想让事件继续传递,可以在路由的某个节点的处理函数中将e.Handled=true,表示事件已经被处理,那么后续的路由中该事件将不会被处理。但是如果使用AddHandler 方法并将第三个参数设置为true ,即使事件在之前被标记为已处理(e.Handled=true),通过AddHandler 方法添加的事件处理函数依然会执行。
下面的例子说明AddHandler 方法第三个参数的具体作用。
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1"
Title="test"
KeyDown="winMain_KeyDown">
<StackPanel Orientation="Vertical" Name="spMain">
<Label Content="Some good movies:"/>
<StackPanel Orientation="Horizontal" Margin="10" KeyDown="spLawrence_KeyDown">
<Label Content="Lawrence of Arabia" FontWeight="Bold"/>
<Label Content="David Lean"/>
<Button Content="Like" Padding="8,0"/>
<TextBox Width="75" Margin="5,2" KeyDown="tbLawrence_KeyDown"/>
</StackPanel>
</StackPanel>
</Window>
上面的XAML代码中
Window下面有两个
StackPanel ,并且在最底层的
StackPanel 中有一个
TextBox 控件,我给
TextBox 和包含它的底层
StackPanel 以及
Window注册
KeyDown 事件,而作为
Window根元素的
StackPanel 在代码中使用
AddHandler 方法注册
KeyDown 事件。
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
spMain.AddHandler(UIElement.KeyDownEvent, (KeyEventHandler)spMain_KeyDown, true);
}
private void tbLawrence_KeyDown(object sender, KeyEventArgs e)
{
DumpInfo("tbLawrence_KeyDown", sender, e.Source);
}
private void spLawrence_KeyDown(object sender, KeyEventArgs e)
{
DumpInfo("spLawrence_KeyDown", sender, e.Source);
e.Handled = true; // The event stops here
}
private void spMain_KeyDown(object sender, KeyEventArgs e)
{
DumpInfo("spMain_KeyDown", sender, e.Source);
}
private void winMain_KeyDown(object sender, KeyEventArgs e)
{
DumpInfo("winMain_KeyDown", sender, e.Source);
}
private void DumpInfo(string title, object sender, object source)
{
System.Console.WriteLine(title + " sender=" + sender.ToString() + " source=" + source.ToString());
}
}
在上面的代码中我们在底层StackPanel 的KeyDown 事件处理函数spLawrence_KeyDown中将事件标记为已处理(e.Handled = true)。这样作为根元素的StackPanel 和Window 的KeyDown 事件处理函数是不会被执行的。事实上如果没有构造函数中的
spMain.AddHandler(UIElement.KeyDownEvent, (KeyEventHandler)spMain_KeyDown, true);
这句代码的确应该是这样,但是通过这句代码作为根元素的StackPanel 注册了事件并标明及时事件被标记为处理依然执行自己的事件处理函数,程序运行后在TextBox中输入一个字符,打印的结果如下:
tbLawrence_KeyDown sender=System.Windows.Controls.TextBox source=System.Windows.Controls.TextBox
spLawrence_KeyDown sender=System.Windows.Controls.StackPanel source=System.Windows.Controls.TextBox
spMain_KeyDown sender=System.Windows.Controls.StackPanel source=System.Windows.Controls.TextBox
可以看到作为根元素的StackPanel 的事件处理函数执行了,但是Window 的事件处理函数没有执行。
参考文章:https://wpf.2000things.com/2012/06/20/584-handling-an-event-that-has-already-been-handled/