如果事件列在RoutedEventArgs,那么它就是路由事件。路由事件支持 Bubble、Tunnel 或 Direct 的 RoutingStrategy。我们来看看Button.Click的事件处理函数:
private void Grid_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show("Button Test clicked!");
}
这里指定了RoutedEventArgs,所以是路由事件。因为 preview 没有在名字中指定,所以这个 Bubble 事件。这可以通过以下方式证明:
<Grid ButtonBase.Click="Grid_Click">
<Button Name="TestButton" Width="100" Height="30" Content="Test" />
</Grid>
当你点击TestButton时,事件会升到Grid之上,并显示一条消息:
按钮测试点击了!
Usefulness of Bubbling/Tunneling strategies
Tunneling
许多标准控件监听事件,例如KeyDown、MouseDown等。例如-DataGrid控件。我想通过按回车键调用该函数添加记录。但是DataGrid 已经有KeyDown 事件,所以不会引发该事件。所以你必须在隧道事件中执行你的逻辑 - PreviewKeyDown,它将在 KeyDown 事件之前工作。这同样适用于RichTextBoxControl。
Bubbling
有时,您需要针对特定事件的全局处理程序,因此它适用于 VisualTree 中的所有控件。自然,一个直接的事件你是做不到的。因此在舞台上出现了冒泡事件。
另一个原因是 WPF 的意识形态。这个Button 可以包含任何东西:Image,另一个Button,等等:
用户可以点击Button中的TextBlock/Image。我们如何知道点击是在Button 中?没错,就是借助 Bubbling 事件。
更多信息,请参见:
Understanding Routed Events and Commands In WPF
Edit
我改变了一点 Click 处理程序:
private void Grid_Click(object sender, RoutedEventArgs e)
{
String message = "#" + eventCounter.ToString() + ":\r\n" +
" Sender: " + sender.ToString() + ":\r\n" +
" Source: " + e.Source + ":\r\n" +
" Original Source: " + e.OriginalSource;
lstEvents.Items.Add(message);
}
点击Button的结果: