WPF学习02:Routed Events

  与传统的桌面开发相比,在事件模型上WPF引入了Routed Events,从开发者的角度上,我们获得了两个便利:

  1.可以实现事件路由,即向XAML结构中的父元素路由或者是向子元素路由。

      2. RoutedEventArgs作为默认的事件Args为我们提供了更多的信息。

事件应用示例

  建立工程“RoutedEvent”,初始的代码修改Grid Layout为StackPanel,添加了一个Button,如下图:

   

  编写Click Event Handler:

 private void ButtonA_Click(object sender, RoutedEventArgs e)
 {
     System.Diagnostics.Debug.WriteLine("Get it");
 }

   我们有两种方式为该按钮添加Click Event Handler:

  XAML形式:

 <Button Name="ButtonA" Click="ButtonA_Click">ButtonA</Button>

   C#形式:

 ButtonA.AddHandler(Button.ClickEvent, new RoutedEventHandler(ButtonA_Click)); 
 ButtonA.Click += ButtonA_Click;  //这样亦可,但只能用于该控件支持的事件

  结果:

  

  注意:一个事件,同一个handler添加多次的结果如下图,是引发Bug的诱因之一:

  

  

RoutedEventArgs

  从上一个例子我们可以看到,WPF事件机制默认提供的EventArgs为RoutedEventArgs

 public delegate void RoutedEventHandler(object sender, RoutedEventArgs e);

  与EventArgs相比,Routed Event提供了4个新的属性.

  RoutedEvent:可以获取到时间的类型,可以在一个Handler处理多个不同类型事件时用上。

  其它三个都与事件路由相关:

  Handled,指定sender是否对该事件继续路由,接下来的例子会展示它的作用。

  Source,该事件的触发源。

  OriginalSource,通常与Source为同一个值。

  

事件路由

  以事件路由模式来分类,WPF提供了3种事件路由模式:

  1. Direct (不路由)
  2. Bubbling events(向上路由)
  3. Tunneling events(向下路由)

  对于一个事件,如果不清楚它的路由模式,可以MSDN查一下:比如:MSDN上关于Click的说明:

  

  直接以例子来说明事件路由的作用:我们修改一下XAML代码,如下:

 <StackPanel>
        <Button Name="ButtonA">ButtonA</Button>
        <Button Name="ButtonB">ButtonB</Button>
        <Button Name="ButtonC">ButtonC</Button>
        <Button Name="ButtonD">ButtonD</Button>
        <Button Name="ButtonE">ButtonE</Button>
        <Button Name="ButtonF">ButtonF</Button>
        <Button Name="ButtonG">ButtonG</Button>
        <Button Name="ButtonH">ButtonH</Button>
 </StackPanel>

  现在界面上有了8个Button,如果需要为8个按钮都做事件处理,那要怎么做呢?通过事件路由我们可以很优雅的解决:

  由于Click为向上路由的事件,我们随便找它的一个父元素,比如stackPanel,填加一句代码就好了:

 <StackPanel Button.Click="Button_Click">

  以下为Handler代码:

private void Button_Click(object sender, RoutedEventArgs e)
{
    System.Diagnostics.Debug.WriteLine("Get Info From {0}", e.Source);
}

  结果:

  

  为顶层Window添加同样的代码会得到相同的结果,因为事件将一直路由到顶层。

  最后,回顾一下刚才RoutedEventArgs中的Handled.

  接下来的例子说明了如何通过设置Handled阻碍事件路由:

  XAML代码:

 <Window x:Class="RoutedEvent.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" Button.Click="Button_Click">
    <StackPanel Name="StackPanelA">
        <Button Name="ButtonA">ButtonA</Button>
        <Button Name="ButtonB">ButtonB</Button>
        <Button Name="ButtonC">ButtonC</Button>
        <Button Name="ButtonD">ButtonD</Button>
        <Button Name="ButtonE">ButtonE</Button>
        <Button Name="ButtonF">ButtonF</Button>
        <Button Name="ButtonG">ButtonG</Button>
        <Button Name="ButtonH">ButtonH</Button>
    </StackPanel>
 </Window>

  C#代码:

  

 public MainWindow()
 {
     InitializeComponent();
     StackPanelA.AddHandler(Button.ClickEvent, new RoutedEventHandler(StackPanel_Click), true);
 }
        
 private void Button_Click(object sender, RoutedEventArgs e)
 {
     System.Diagnostics.Debug.WriteLine("Get Info From {0}", e.Source);
 }

 private void StackPanel_Click(object sender, RoutedEventArgs e)
 {
    System.Diagnostics.Debug.WriteLine("I will block the routing", e.Source);
    e.Handled = true;
 }

  结果:事件路由将到了StackPanel即被阻碍,Window的对于Click 的Handler将不会触发,大家可以试试。

原文地址:https://www.cnblogs.com/E-WALKER/p/4371992.html