什么是路由事件
路由事件是一种可以针对元素树中的多个侦听器而不是仅仅针对引发该事件的对象调用处理程序的事件。路由事件是一个CLR事件。
我们使用路由事件以下三种路由策略之一:冒泡
XAML代码如下:
<Window x:Class="WpfRouteEventByBubble.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="190" Width="246" WindowStartupLocation="CenterScreen">
<Grid x:Name="GridRoot" Background="Lime">
<Grid x:Name="GridA" Margin="10" Background="Blue">
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<Canvas x:Name="CanvasLeft" Grid.Column="0" Background="Red" Margin="10">
<Button x:Name="ButtonLeft" Width="65" Height="100" Margin="10" Content="Left"></Button>
</Canvas>
<Canvas x:Name="CanvasRight" Grid.Column="1" Background="Yellow" Margin="10">
<Button x:Name="ButtonRight" Width="65" Height="100" Margin="10" Content="Right"></Button>
</Canvas>
</Grid>
</Grid>
</Window>
运行效果如下所示:
当单击Left按钮的时候,Button.Click事件被触发,并且沿着ButtonLeft→CanvasLeft→GridA→GridRoot→Window这条路线向上传递,当单击Right按钮就会沿着ButtonRight→CanvasRight→GridA→GridRoot→Window这条路线向上传递,这里还没有添加监听器,所以是没有反应的。
如何加入监听器,我们可以再XAML中添加,XAML代码如下:
<Window x:Class="WpfRouteEventByBubble.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="190" Width="246" WindowStartupLocation="CenterScreen">
<Grid x:Name="GridRoot" Background="Lime" Button.Click="Button_Click">
<Grid x:Name="GridA" Margin="10" Background="Blue" Button.Click="Button_Click">
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<Canvas x:Name="CanvasLeft" Grid.Column="0" Background="Red" Margin="10" Button.Click="Button_Click">
<Button x:Name="ButtonLeft" Width="65" Height="100" Margin="10" Content="Left" Button.Click="Button_Click"></Button>
</Canvas>
<Canvas x:Name="CanvasRight" Grid.Column="1" Background="Yellow" Margin="10" Button.Click="Button_Click">
<Button x:Name="ButtonRight" Width="65" Height="100" Margin="10" Content="Right" Button.Click="Button_Click"></Button>
</Canvas>
</Grid>
</Grid>
</Window>
我们在XAML代码中添加了Button.Click="Button_Click"这个事件处理器,就是监听器,并且事件处理交由Button_Click负责,后台Button_Click代码如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace WpfRouteEventByBubble
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show("我到达了:" + (sender as FrameworkElement).Name);
}
}
}
我们分析一下,那两个参数到底是什么呢?
参数一:sender,这是听者,就是监听的地方,如果点击了Left按钮,那么Left按钮就会大声说:“我被点击了”这个事件向上传递,知道到了设有监听Button.Click事件的地方,这个地方就是sender。
参数二:是RoutEventArgs类型的,这个参数携带了一些重要信息,例如事件是从哪里来的,上一个传到哪里等,都可以利用这个参数来查询。
运行效果如下:
我们会发现,当点击button按钮时,ButtonLeft、CanvasLeft、GridA、GridRoot中的事件都会触发,这就是冒泡路由策略的功能所在,事件首先在源元素上触发,然后从每一个元素向上沿着树传递,直到到达根元素为止(或者直到处理程序把事件标记为已处理为止),从而调用这些元素中的路由事件。
如果把Button_Click事件修改为:
private void Button_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show("我到达了:" + (sender as FrameworkElement).Name);
e.Handled = true;//让事件停止冒泡
}
则以上事件就不会沿着ButtonLeft→CanvasLeft→GridA→GridRoot→Window这条路线传递下去,只会执行ButtonLeft的事件。