路由事件概述
功能定义:路由事件是一种可以针对元素树中的多个侦听器(而不是仅针对引发该事件的对象)调用处理程序的事件。
实现定义:路由事件是一个 CLR 事件,可以由RouteEvent 类的实例提供支持并由 Windows Presentation Foundation (WPF) 事件系统来处理。
实例:
Xaml
<Border Height="50" Width="300" BorderBrush="Gray" BorderThickness="1"> <StackPanel Background="LightGray" Orientation="Horizontal" Button.Click="CommonClickHandler"> <Button Name="YesButton" Width="Auto" >Yes</Button> <Button Name="NoButton" Width="Auto" >No</Button> <Button Name="CancelButton" Width="Auto" >Cancel</Button> </StackPanel> </Border>
class="sentence" data-guid="c5ddc1060b7fdbb103762a142fb97d2d" data-source="In this simplified element tree, the source of a <span class="mtpsTagOuterHtml" >Click event is one of the <span class="mtpsTagOuterHtml" >Button elements, and whichever <span class="mtpsTagOuterHtml" >Button was clicked is the first element that has the opportunity to handle the event.">在这个简化的元素树中,Click事件的源是某个 Button元素,而所单击的 Button是有机会处理该事件的第一个元素。 但是,如果附加到 Button的任何处理程序均未作用于该事件,则该事件将向上冒泡到元素树中的 Button父级(即 StackPanel)。 该事件可能会冒泡到 Border,然后会到达元素树的页面根(未显示出来)。
换言之,此Click事件的事件路由为:Button-->StackPanel-->Border-->...
路由事件的策略
Bubbling:路由事件随后会路由到后续的父元素,直到到达元素树的根。
Direct:只有源元素本身才有机会调用处理程序以进行响应
Tunneling:最初将在元素树的根处调用事件处理程序。
路由事件策略会因为一下因素改变:
事件处理函数
public delegate void RoutedEventHandler(Object Sender, RoutedEventArgs e);
public delegate void MouseEventHandler(Object Sender, MouseEventArgs e);
RoutedEventArgs和MouseEventArgs包含路由事件的信息
如果设置"Handled"属性为True,路由事件会停止传递
类和实例事件处理函数
事件处理函数有两种类型,前一种是普通事件处理函数,"实例事件处理函数",另一种是通过EventManager.RegisterClassHandler方法将一个事件处理函数和类关联起来,"类事件处理函数",优先级更高
实例:(取自《葵花宝典--WPF自学手册》6.5)
自定义Button类
public class MySimpleButton : Button { static MySimpleButton() { EventManager.RegisterClassHandler(typeof(MySimpleButton), CustomClickEvent, new RoutedEventHandler(CustomClickClassHandler), false); } public event EventHandler ClassHandlerProcessed; public static void CustomClickClassHandler(Object sender, RoutedEventArgs e) { MySimpleButton simpBtn = sender as MySimpleButton; EventArgs args = new EventArgs(); simpBtn.ClassHandlerProcessed(simpBtn, e); } //Create and register routed event, routing strategies: Bubble public static readonly RoutedEvent CustomClickEvent = EventManager.RegisterRoutedEvent( "CustomClick", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(MySimpleButton)); //CLR event wrapper public event RoutedEventHandler CustomClick { add { AddHandler(CustomClickEvent, value); } remove { RemoveHandler(CustomClickEvent, value); } } //Raise CustomClickEvent void RaiseCustomClickEvent() { RoutedEventArgs newEventArgs = new RoutedEventArgs(MySimpleButton.CustomClickEvent); RaiseEvent(newEventArgs); } //Onclick protected override void OnClick() { RaiseCustomClickEvent(); } }
MainWindow.xaml
<Window x:Class="Alex_WPFAPPDemo02.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:custom="clr-namespace:Alex_WPFAPPDemo02" custom:MySimpleButton.CustomClick="InsertList" Title="MainWindow" Height="350" Width="525"> <Grid Margin="3" custom:MySimpleButton.CustomClick="InsertList" Name="Grid1"> <Grid.RowDefinitions> <RowDefinition Height="Auto" /> <RowDefinition Height="*" /> <RowDefinition Height="Auto" /> <RowDefinition Height="Auto" /> </Grid.RowDefinitions> <custom:MySimpleButton x:Name="simpBtn" CustomClick="InsertList"> My Simple Button </custom:MySimpleButton> <ListBox Margin="5" Name="listBox" Grid.Row="1" /> <CheckBox Margin="5" Grid.Row="2" Name="chkHandle"> Handle first event </CheckBox> <Button Grid.Row="3" HorizontalAlignment="Right" Margin="5" Padding="3" Click="clear"> Clear List </Button> </Grid> </Window>
MainWindow.xaml.cs
protected int eventCounter = 0; private void InsertList(object sender, RoutedEventArgs e) { eventCounter++; string message = "#" + eventCounter.ToString() + ":\r\n" + "InsertList\r\n" + " Sender: " + sender.ToString() + "\r\n" + " Source: " + e.Source + "\r\n" + "Original Source: " + e.OriginalSource; listBox.Items.Add(message); e.Handled = (bool)chkHandle.IsChecked; } private void clear(object sender, RoutedEventArgs e) { eventCounter = 0; listBox.Items.Clear(); }
添加类处理函数
static MySimpleButton() { EventManager.RegisterClassHandler(typeof(MySimpleButton), CustomClickEvent, new RoutedEventHandler(CustomClickClassHandler), false); } public event EventHandler ClassHandlerProcessed; public static void CustomClickClassHandler(Object sender, RoutedEventArgs e) { MySimpleButton simpBtn = sender as MySimpleButton; EventArgs args = new EventArgs(); simpBtn.ClassHandlerProcessed(simpBtn, e); }
完善代码
public MainWindow() { InitializeComponent(); this.simpBtn.ClassHandlerProcessed += new EventHandler(ButtonRaisedClass); }private void ButtonRaisedClass(object sender, EventArgs e) { eventCounter++; string message = "#" + eventCounter.ToString() + ":\r\n" + "Windows Class Handler\r\n" + " Sender: " + sender.ToString(); listBox.Items.Add(message); } private void ProcessHanldersToo(Object sender, RoutedEventArgs e) { eventCounter++; string message = "#" + eventCounter.ToString() + ":\r\n" + "ProcessHanldersToo\r\n" + " Sender: " + sender.ToString() + " Source: " + e.Source + "\r\n" + "Original Source: " + e.OriginalSource; listBox.Items.Add(message); } private void Window_Loaded(object sender, RoutedEventArgs e) { Grid1.AddHandler(MySimpleButton.CustomClickEvent, new RoutedEventHandler(ProcessHanldersToo), true); }
可以查看路由事件的线路
To be continue...