本文摘要:
1:什麼是路由事件;
2:中斷事件路由;
3:自定義路由事件;
4:為什麼需要自定義路由事件;
5:什麼是冒泡事件和預覽事件(隧道事件);
1:什麼是路由事件
WPF中的事件為路由事件,所謂路由事件,MSDN定義如下:
功能定義:路由事件是一種可以針對元素樹中的多個偵聽器(而不是僅針對引發該事件的對象)調用處理程式的事件。
實作定義:路由事件是一個 CLR 事件,可以由
RoutedEvent類的執行個體提供支援并由 Windows Presentation Foundation (WPF) 事件系統來處理。
但這兩類定義都比較抽象,我們來看更具體的定義:
<Border Height="50" Width="250" BorderBrush="Gray" BorderThickness="1" >
<StackPanel Background="LightGray" Orientation="Horizontal" MouseUp="StackPanel_MouseUp">
<TextBlock Name="YesTB" Width="50" MouseUp="YesTB_MouseUp" Background="Blue" >Yes</TextBlock>
</StackPanel>
</Border>
在這個例子中,事件的事件路由為:
TextBlock -->StackPanel-->Border —>...
2:中斷事件路由 所有的路由事件都共享一個公共的事件資料基類
RoutedEventArgs。
定義了一個采用布爾值的
Handled屬性。
屬性的目的在于,允許路由中的任何事件處理程式通過将
的值設定為 true 來将路由事件标記為“已處理”。
private void StackPanel_MouseUp(object sender, MouseButtonEventArgs e)
{
MessageBox.Show("Panel");
}
private void YesTB_MouseUp(object sender, MouseButtonEventArgs e)
{
MessageBox.Show("button");
e.Handled = true;
}
在上面的例子中,将不再觸發StackPanel_MouseUp事件。
3:自定義路由事件
如下面的示例所示,首先使用
RegisterRoutedEvent方法注冊一個
。按照約定,
靜态字段名稱應當以字尾 Event 結束。在本示例中,事件的名稱是 Tap,事件的路由政策是
Bubble。在注冊調用之後,可以為該事件提供添加和移除公共語言運作時 (CLR) 事件通路器。
請注意,盡管該事件在本特定示例中是通過 OnTap 虛方法引發的,但您引發事件的方式或者事件響應更改的方式取決于您的需要。
還要注意,本示例主要實作
Button的一整個子類;該子類是作為單獨的程式集建構的,之後将在單獨的可擴充應用程式标記語言 (XAML) 頁上執行個體化為一個自定義類。這是為了說明這樣一個概念:建立子類的控件可以插入到由其他控件組成的樹中,在這種情況下,這些控件上的自定義事件具有與任何固有的 Windows Presentation Foundation (WPF) 元素完全相同的事件路由功能。
public class MyButtonSimple: Button
{
// Create a custom routed event by first registering a RoutedEventID
// This event uses the bubbling routing strategy
public static readonly RoutedEvent TapEvent = EventManager.RegisterRoutedEvent(
"Tap", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(MyButtonSimple));
// Provide CLR accessors for the event
public event RoutedEventHandler Tap
{
add { AddHandler(TapEvent, value); }
remove { RemoveHandler(TapEvent, value); }
}
// This method raises the Tap event
void RaiseTapEvent()
{
RoutedEventArgs newEventArgs = new RoutedEventArgs(MyButtonSimple.TapEvent);
RaiseEvent(newEventArgs);
}
// For demonstration purposes we raise the event when the MyButtonSimple is clicked
protected override void OnClick()
{
RaiseTapEvent();
}
}
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:custom="clr-namespace:SDKSample;assembly=SDKSampleLibrary"
x:Class="SDKSample.RoutedEventCustomApp"
>
<Window.Resources>
<Style TargetType="{x:Type custom:MyButtonSimple}">
<Setter Property="Height" Value="20"/>
<Setter Property="Width" Value="250"/>
<Setter Property="HorizontalAlignment" Value="Left"/>
<Setter Property="Background" Value="#808080"/>
</Style>
</Window.Resources>
<StackPanel Background="LightGray">
<custom:MyButtonSimple Name="mybtnsimple" Tap="TapHandler">Click to see Tap custom event work</custom:MyButtonSimple>
</StackPanel>
</Window>
4:為什麼需要自定義路由事件
一直到目前看來,我們都不太需要自定義的路由事件。但是,在我們建立自定義控制的時候,建立一些和業務相關的路由事件,就顯得很有必要。
如,建立一個線上考試中的題型展示控件,可以為該控件設計一個自定義事件,為“送出”。這樣一來,這個題型控件不僅僅隻有一些通用事件,還可以看上去更“業務”。
5:什麼是冒泡事件和預覽事件(隧道事件)
路由事件實際上分兩類:冒泡事件和預覽事件(隧道事件)。上文中的例子就是冒泡事件。
冒泡事件是WPF路由事件中最為常見,它表示事件從源元素擴散(傳播)到可視樹,直到它被處理或到達根元素。這樣您就可以針對源元素的上方層級對象處理事件。例如,您可向嵌入的 Grid 元素附加一個 Button.Click 處理程式,而不是直接将其附加到按鈕本身。氣泡事件有訓示其操作的名稱(例如,MouseDown)。
隧道事件采用另一種方式,從根元素開始,向下周遊元素樹,直到被處理或到達事件的源元素。這樣上遊元素就可以在事件到達源元素之前先行截取并進行處理。根據命名慣例,隧道事件帶有字首 Preview(例如 PreviewMouseDown)。
在本文一開始的例子中,如果我們将MouseUP,改為PreviewMouseUP,效果會如何呢。
差別:
冒泡事件:在YesTB上點選,首先彈出“button”,再彈出“panel”。
預覽事件(隧道事件)事件:在YesTB上點選,首先彈出“panel”,再彈出“button”。
看到了這點差別,那麼我們加入e.Handled=true的時機也要不同。首先,
冒泡事件例子中:e.Handled=true加在YesTB_PreviewMouseUp中,加入後,點選YesTB,将隻彈出“button”。
預覽事件(隧道事件)例子中:e.Handled=true家在StackPanel_PreviewMouseUp中,加入後,點選YesTB,将隻彈出“panel”。