路由事件概觀
本主題描述 Windows Presentation Foundation (WPF) 中路由事件的概念。 本主題會定義路由事件的術語、說明如何透過元素的樹狀結構路由傳送路由事件、摘要說明如何處理路由事件,以及介紹如何建立您自己的自訂路由事件。
必要條件
本主題假設您已瞭解 Common Language Runtime (CLR) 和面向物件程式設計的基本知識,以及 WPF 元素之間的關聯性如何概念化為樹狀結構的概念。 為了遵循本主題中的範例,您也應該瞭解可延伸的應用程式標記語言(XAML),並知道如何撰寫非常基本的 WPF 應用程式或頁面。 如需詳細資訊,請參閱 逐步解說:我的第一個 WPF 傳統型應用程式 和 WPF 中的 XAML。
什麼是路由事件?
您可以從功能或實作觀點來考量路由事件。 此處說明這兩個定義,讓使用者能夠選擇較實用的定義。
功能定義︰路由事件是一種事件類型,可在元素樹狀結構中的多個接聽程式上叫用處理常式,而不只是在引發事件的物件上。
實作定義:路由事件是CLR事件,由 RoutedEvent 類別的實例支援,並由Windows Presentation Foundation (WPF) 事件系統處理。
典型的 WPF 應用程式包含許多元素。 無論是在程序代碼中建立或在 XAML 中宣告,這些元素都存在於彼此的元素樹狀結構關聯性中。 事件路由的周遊方向取決於事件定義,但通常路由會從來源元素開始周遊,然後透過元素樹狀結構向上執行「事件反昇」,直到它到達元素樹狀結構根元素 (通常是頁面或視窗) 為止。 如果您先前曾用過 DHTML 物件模型,可能很熟悉這個事件反昇概念。
請考慮下列簡單的元素樹狀結構:
<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>
這個元素樹狀結構會產生如下的畫面:
在這個簡化的專案樹狀結構中,Click事件的來源是其中一個Button元素,並且,Button有機會處理事件的首要元素將被選擇。 但是,對於事件如果沒有附加的Button處理程式,事件會向上反升至元素樹狀結構中的Button父元素,也就是 StackPanel。 事件可能會反升到 Border,然後超越元素樹的頁面根(未顯示)。
換句話說,此Click事件的事件路由為:
Button-->StackPanel-->Border-->...
路由事件的最上層案例
以下是激勵路由事件概念的案例簡短摘要,以及為什麼一般 CLR 事件不適合這些案例:
控件組合和封裝: WPF 中的各種控件都有豐富的內容模型。 例如,您可以將影像放在 Button內,這會有效地擴充按鈕的可視化樹狀結構。 不過,新增的影像不得中斷點擊測試行為,導致按鈕回應 Click 的內容,即使使用者按下圖片一部分的圖元也一樣。
單一處理程式附件點: 在 Windows Forms 中,您必須多次附加相同的處理程式來處理可能從多個元素引發的事件。 路由事件可讓您只需附加該處理常式一次 (如上一個範例中所示),然後就能視需要使用處理常式邏輯判斷此事件來自何處。 例如,這可能是先前所顯示 XAML 的處理程式:
private void CommonClickHandler(object sender, RoutedEventArgs e)
{
FrameworkElement feSource = e.Source as FrameworkElement;
switch (feSource.Name)
{
case "YesButton":
// do something here ...
break;
case "NoButton":
// do something ...
break;
case "CancelButton":
// do something ...
break;
}
e.Handled=true;
}
Private Sub CommonClickHandler(ByVal sender As Object, ByVal e As RoutedEventArgs)
Dim feSource As FrameworkElement = TryCast(e.Source, FrameworkElement)
Select Case feSource.Name
Case "YesButton"
' do something here ...
Case "NoButton"
' do something ...
Case "CancelButton"
' do something ...
End Select
e.Handled=True
End Sub
類別處理:路由事件允許類別所定義的靜態處理常式。 這個類別處理常式有機會在任何附加的執行個體處理常式之前處理事件。
參考事件,但不使用反射:特定程式碼和標記技術需要識別特定事件的方式。 路由事件建立一個 RoutedEvent 欄位做為識別項,以提供不需要靜態或執行階段反映的強固事件識別技術。
路由事件的實作方式
路由事件是 CLR 事件,由 RoutedEvent 類別的實例支援,並且向 WPF 事件系統註冊。 從註冊取得的 RoutedEvent 實例通常會保留為註冊之類別的 public
static
readonly
欄位成員,因此會「擁有」路由事件。 透過覆寫 CLR 事件的 add
和 remove
實作來完成與同名 CLR 事件的連接(有時稱為「包裝函式」事件)。 一般而言,add
和 remove
會保留為隱含的預設值,以使用適當的語言特定事件語法來加入和移除該事件的處理常式。 路由事件支援和連接機制在概念上類似於相依性屬性是CLR屬性的方式,該屬性是由 DependencyProperty 類別所支援,並且向WPF屬性系統註冊。
下列範例顯示自定義 Tap
路由事件的宣告,包括 RoutedEvent 標識符欄位的註冊和曝光,以及為了 Tap
CLR 事件的 add
和 remove
實作。
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); }
}
Public Shared ReadOnly TapEvent As RoutedEvent = EventManager.RegisterRoutedEvent("Tap", RoutingStrategy.Bubble, GetType(RoutedEventHandler), GetType(MyButtonSimple))
' Provide CLR accessors for the event
Public Custom Event Tap As RoutedEventHandler
AddHandler(ByVal value As RoutedEventHandler)
Me.AddHandler(TapEvent, value)
End AddHandler
RemoveHandler(ByVal value As RoutedEventHandler)
Me.RemoveHandler(TapEvent, value)
End RemoveHandler
RaiseEvent(ByVal sender As Object, ByVal e As RoutedEventArgs)
Me.RaiseEvent(e)
End RaiseEvent
End Event
路由事件處理常式和 XAML
若要使用 XAML 新增事件的處理程式,請將事件名稱宣告為事件接聽程式之專案上的屬性。 屬性的值是您所實作之處理常式方法的名稱,此名稱必須存在於程式碼後置檔案的部分類別中。
<Button Click="b1SetColor">button</Button>
新增標準 CLR 事件處理程式的 XAML 語法與新增路由事件處理程式相同,因為您確實將處理程式新增至 CLR 事件包裝函式,其下方有路由事件實作。 如需在 XAML 中新增事件處理程式的詳細資訊,請參閱在 WPF 中 XAML。
路由傳送策略
路由事件會使用下列其中一個路由傳送策略:
事件反昇︰會叫用事件來源上的事件處理常式。 路由事件接著會路由傳送到後續的父元素,直到其到達元素樹狀結構的根元素為止。 大部分的路由事件會使用事件反昇路由傳送策略。 事件反昇的路由事件通常是用來報告來自不同控制項或其他 UI 元素的輸入或狀態變更。
直接︰只有來源元素本身有機會叫用處理常式來回應。 這類似於 Windows Forms 用於事件的「路由」。 不過,不同於標準 CLR 事件,直接路由事件支援類別處理(下一段中會說明類別處理),而且可由 EventSetter 和 EventTrigger使用。
通道︰一開始會叫用元素樹狀結構根元素上的事件處理常式。 路由事件接著會在路由中朝向屬於路由事件來源的節點元素 (會引發路由事件的元素) 移動,以透過後續的子元素周遊該路由。 通道路由事件時常會做為複合控制項的一部分來使用或處理,這類來自複合組件的事件可利用專用於該完整控制項的事件來刻意隱藏或取代。 WPF 中提供的輸入事件通常會實作為通道/反升組。 由於用於配對的命名慣例,通道事件有時也稱為預覽事件。
為什麼要使用路由事件?
身為應用程式開發人員,您不一定需要知道或在意要將您正在處理的事件實作為路由事件。 路由事件都有特殊的行為,但是,如果您正在引發事件的元素上處理該事件,則大多不會看見該行為。
路由事件變成功能強大之處在於,您是否使用任何建議的案例︰在一般的根元素上定義一般的處理常式、組合自己的控制項,或定義自己的控制項類別。
路由事件接聽程式和路由事件來源不需要在其階層中共用一般事件。 任何 UIElement 或 ContentElement 可以是任何路由事件的事件接聽程式。 因此,您可以使用整個工作 API 集合中可用的完整路由事件集做為概念性的「介面」,讓應用程式中不同的元素可以交換事件資訊。 路由事件的這個「介面」概念特別適用於輸入事件。
路由事件也可用來透過元素樹狀結構進行通訊,因為事件的事件資料會永久存在於路由的每個元素中。 一個元素可以變更事件資料中的某些內容,而該變更可供路由中的下一個元素使用。
除了路由層面之外,還有其他兩個原因,任何指定的 WPF 事件都可能實作為路由事件,而不是標準 CLR 事件。 如果您要實作自己的事件,也可以考慮這些準則:
某些 WPF 樣式和範本化功能,例如 EventSetter 和 EventTrigger 需要參考的事件成為路由事件。 這是先前所述的事件識別碼案例。
路由事件支援類別處理機制,此類別可藉以指定靜態方法,有機會在任何已註冊的執行個體處理常式可存取路由事件之前處理它們。 這在控制項設計中非常有用,因為您的類別可以強制執行事件驅動的類別行為,您無法藉由處理執行個體上的事件來附帶隱藏這類行為。
上述每個考量都會在本主題的不同小節中加以討論。
加入和實作路由事件的事件處理常式
若要在 XAML 中新增事件處理程式,您只需將事件名稱新增至專案做為屬性,並將屬性值設定為實作適當委派的事件處理程式名稱,如下列範例所示。
<Button Click="b1SetColor">button</Button>
b1SetColor
是實作處理程式的名稱,其中包含處理 Click 事件的程序代碼。 b1SetColor
必須具有與 RoutedEventHandler 委派相同的簽章,這是 Click 事件的事件處理程式委派。 所有路由事件處理常式委派的第一個參數會指定要加入事件處理常式的元素,而第二個參數會指定事件的資料。
void b1SetColor(object sender, RoutedEventArgs args)
{
//logic to handle the Click event
}
Private Sub b1SetColor(ByVal sender As Object, ByVal args As RoutedEventArgs)
'logic to handle the Click event
End Sub
RoutedEventHandler 是基本的路由事件處理程式委派。 如果是針對特定控制項或案例特製化的路由事件,用於路由事件處理常式的委派也可能會變得更特製化,讓它們能夠傳輸特製化的事件資料。 例如,在常見的輸入案例中,您可能會處理 DragEnter 路由事件。 您的處理程式應該實作 DragEventHandler 委派。 藉由使用最特定的委派,您可以在處理程式中處理 DragEventArgs ,並讀取 Data 屬性,其中包含拖曳作業的剪貼簿承載。
如需如何使用 XAML 將事件處理程式新增至專案的完整範例,請參閱 處理路由事件。
在使用程式碼建立的應用程式中加入路由事件的處理常式很簡單。 路由事件處理程式一律可以透過協助程式方法新增 AddHandler (這與現有支援呼叫 add
的方法相同。)不過,現有的 WPF 路由事件通常具有支援 add
和 remove
邏輯的實作,可讓特定語言事件語法新增路由事件的處理程式,比起協助程式方法為更直覺式的語法。 以下是 Helper 方法的使用方式範例:
void MakeButton()
{
Button b2 = new Button();
b2.AddHandler(Button.ClickEvent, new RoutedEventHandler(Onb2Click));
}
void Onb2Click(object sender, RoutedEventArgs e)
{
//logic to handle the Click event
}
Private Sub MakeButton()
Dim b2 As New Button()
b2.AddHandler(Button.ClickEvent, New RoutedEventHandler(AddressOf Onb2Click))
End Sub
Private Sub Onb2Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
'logic to handle the Click event
End Sub
下一個範例顯示 C# 運算符語法(Visual Basic 因處理取值而具有稍微不同的運算符語法):
void MakeButton2()
{
Button b2 = new Button();
b2.Click += new RoutedEventHandler(Onb2Click2);
}
void Onb2Click2(object sender, RoutedEventArgs e)
{
//logic to handle the Click event
}
Private Sub MakeButton2()
Dim b2 As New Button()
AddHandler b2.Click, AddressOf Onb2Click2
End Sub
Private Sub Onb2Click2(ByVal sender As Object, ByVal e As RoutedEventArgs)
'logic to handle the Click event
End Sub
如需如何在程式碼中加入事件處理常式的範例,請參閱使用程式碼加入事件處理常式。
如果您使用 Visual Basic,您也可以使用 Handles
關鍵詞,將處理程式新增為處理程式宣告的一部分。 如需詳細資訊,請參閱 Visual Basic 和 WPF 事件處理。
已處理的概念
所有路由事件都會共用一般事件數據基類, RoutedEventArgs。 RoutedEventArgs 採用布林值定義 Handled 屬性。 Handled 屬性的目的是讓路由上的任何事件處理程式將路由事件標示為 處理,方法是將 Handled 的值設定為 true
。 透過處理常式在路由中的某一個元素上進行處理之後,就會再次向路由中的每一個接聽程式報告共用的事件資料。
Handled 值會影響路由事件在沿著路線進一步移動時報告或處理的方式。 如果路由事件的事件數據中 true
Handled ,則其他元素上接聽該路由事件的處理程式通常不會再針對該特定事件實例喚醒。 這適用於附加在 XAML 中的處理程式,以及由語言特定事件處理程式附件語法所新增的處理程式,例如 +=
或 Handles
。 針對最常見的處理程式案例,將事件透過將 Handled 設定為 true
並標示為處理完成,會「停止」通道路由與反升路由的路由傳送,以及針對類別處理程式在路由中某個時間點處理的任何事件。
不過,有一種「handledEventsToo」機制,讓接聽程式仍然可以執行處理程式,以回應事件數據中 Handled true
的路由事件。 換句話說,事件路由無法藉由將事件資料標示為已處理來真正停止。 您只能在程式代碼或 EventSetter中使用 handledEventsToo 機制:
在程式代碼中,使用WPF方法 AddHandler(RoutedEvent, Delegate, Boolean) 來新增處理程式,而不是使用適用於一般 CLR 事件的語言特定事件語法。 將
handledEventsToo
的值指定為true
。在 EventSetter中,將 HandledEventsToo 屬性設定為
true
。
除了 Handled 狀態在路由事件中產生的行為之外, Handled 的概念還會影響您應該如何設計應用程式及撰寫事件處理程式程序代碼。 您可以藉由公開路由事件將 Handled 概念化為檢簡易的通訊協定。 使用此通訊協定的方式完全由您決定,但 Handled 值應如何使用的概念設計如下:
如果將路由事件標示為已處理,則不需再次透過該路由中的其他元素來處理它。
如果未將路由事件標示為已處理,則先前沿著路由的其他接聽程式已選擇不註冊處理程式,或已註冊的處理程式選擇不操作事件數據,並將 Handled 設定為
true
。 (或者,當然有可能目前的接聽程式為路由中的第一個點)。目前接聽程式上的處理常式現在有三個可能的做法:不採取任何動作;事件會保持未處理狀態,而事件會路由傳送到下一個接聽程式。
執行程式碼以回應事件,但判定採取的動作後續不足以保證會將事件標示為已處理。 事件會路由傳送到下一個接聽程式。
執行程式碼以回應事件。 在傳遞至處理常式的事件資料中將事件標示為已處理,因為已將所採取的動作視為後續不足以保證會標示為已處理。 事件仍會路由傳送至下一個接聽程式,但事件數據中有 Handled=
true
,因此只有handledEventsToo
接聽程式有機會叫用進一步的處理程式。
這個概念性設計是根據先前所述的路由傳送行為來加強︰比起附加喚醒之路由事件的處理程式來說更困難 (儘管還是有可能利用程式碼或樣式設定來完成),即使路由中的上一個處理程式已將 Handled 設定為 true
也一樣。
如需有關 Handled、路由事件的類別處理,以及建議何時適當將路由事件標示為 Handled的詳細資訊,請參閱 將路由事件標示為已處理,以及類別處理。
在應用程式中,只在引發事件反昇路由事件的物件上處理該事件是相當常見的,而這並不完全與事件的路由特性有關。 不過,它仍是在事件資料中將路由事件標示為已處理的最佳做法,萬一元素樹狀結構中進一步向上的元素也具有已針對該相同路由事件附加的處理常式時,可避免發生未預期的副作用。
類別處理常式
如果您要定義衍生自 DependencyObject的類別,您也可以定義和附加路由事件的類別處理程式,該事件是宣告或繼承類別成員。 每當路由事件到達其路由中的元素執行個體時,就可以在任何附加至該類別執行個體的執行個體接聽程式處理常式之前叫用類別處理常式。
某些 WPF 控制項具有特定路由事件的固有類別處理。 這可能會造成表面上未曾引發過路由事件,但實際上卻已處理過類別的情況,而且,如果您使用某些技術,您的執行個體處理常式可能仍會處理該路由事件。 此外,許多基底類別和控制項會公開可用於覆寫類別處理行為的虛擬方法。 如需如何因應不想要的類別處理,並在自訂類別中定義您自己之類別處理的詳細資訊,請參閱將路由事件標記為已處理以及類別處理。
在 WPF 中附加事件
XAML 語言也定義為特殊事件,稱為 附加事件 。 附加事件可讓您將特殊事件的處理常式加入至任意元素。 處理事件的元素不需要定義或繼承附加事件,而物件不可能引發事件,且目的地處理執行個體也不需定義或「擁有」該事件做為類別成員。
WPF 輸入系統廣泛使用附加事件。 不過,幾乎這所有的附加事件都會轉送到基底元素。 輸入事件接著會顯示為對等的非附加路由事件,其為基底元素類別的成員。 例如,基礎附加事件 Mouse.MouseDown 可以更輕鬆地在該 UIElement 上使用 MouseDown 來處理任何指定的 UIElement ,而不是在 XAML 或程式碼中處理附加事件語法。
如需 WPF 中附加事件的詳細資訊,請參閱 附加事件概觀。
XAML 中的完整事件名稱
類似 typename.eventname 附加事件語法的另一種語法用法 (但嚴格來說,它不是附加事件的使用方式) 是,當您連接由子元素所引發之路由事件的處理常式時。 您可將處理常式附加到共同父項,以利用事件路由,即使共同父項可能沒有相關的路由事件做為成員。 再看一下這個範例:
<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>
在這裡,新增處理程式的父元素接聽程式是 StackPanel。 不過,它會為宣告的路由事件新增處理程式,並由 Button 類別引發(實際上ButtonBase ,但可透過繼承 Button )。 Button 「擁有」事件,但路由事件系統允許任何路由事件的處理程式附加至任何 UIElement 或 ContentElement 實例接聽程式,否則可能會附加 Common Language Runtime (CLR) 事件的接聽程式。 這些合格事件屬性名稱的預設 xmlns 命名空間通常是預設的 WPF xmlns 命名空間,但您也可以為自定義路由事件指定前置命名空間。 如需 xmlns 的詳細資訊,請參閱 WPF XAML 的 XAML 命名空間和命名空間對應。
WPF 輸入事件
WPF 平臺內路由事件的一個常見應用是輸入事件。 在 WPF 中,通道路由事件名稱前面會加上慣例的 “Preview” 一詞。 輸入事件通常會成對出現,其中一個是事件反昇事件,另一個則是通道事件。 例如, KeyDown 事件和 PreviewKeyDown 事件具有相同的簽章,而前者是反升輸入事件,後者則是通道輸入事件。 有時,輸入事件只會有事件反昇版本,或可能只有直接路由版本。 在文件中,路由事件主題會交互參考具備替代路由傳送策略的類似路由事件 (如果這類路由事件存在),而受管理參考頁面中的章節會釐清每個路由事件的路由傳送策略。
實作成對的 WPF 輸入事件,讓輸入中的單一用戶動作,例如按下滑鼠按鈕,將會依序引發配對的兩個路由事件。 首先,引發通道事件,並周遊其路由。 接著,引發事件反昇事件,並周遊其路由。 這兩個事件實際上會共用相同的事件數據實例,因為實作類別中的 RaiseEvent 方法呼叫會引發反升事件接聽來自通道事件的事件數據,並在新的引發事件中重複使用它。 具有通道事件處理常式的接聽程式有機會優先將路由事件標示為已處理 (第一個是類別處理常式,然後是執行個體處理常式)。 如果將通道路由中的元素標示為已處理,則已經處理的事件資料就會針對事件反昇事件進行傳送,而且將不會叫用基於對等事件反昇輸入事件附加的一般處理常式。 表面上來看,就如同未曾引發過已處理的事件反昇事件。 這個處理行為非常適用於控制項複合,您可能想要讓您的最終控制項 (而不是它的複合組件) 報告所有以點擊測試為基礎的輸入事件或以焦點為基礎的輸入事件。 最後一個控制項元素更接近複合中的根元素,因此有機會優先對通道事件進行類別處理,而且,或許可利用更專屬於控制項的事件,做為支援控制項類別的程式碼一部分來「取代」該路由事件。
如需輸入事件處理如何運作的圖表說明,請考量下列輸入事件範例。 在下列樹狀圖中, leaf element #2
是 PreviewMouseDown
和 MouseDown
事件的來源:
事件處理的順序如下:
根元素上的
PreviewMouseDown
(通道)。中繼元素 #1 上的
PreviewMouseDown
(通道)。來源元素 #2 上的
PreviewMouseDown
(通道)。來源元素 #2 上的
MouseDown
(事件反昇)。中繼元素 #1 上的
MouseDown
(事件反昇)。根元素上的
MouseDown
(事件反昇)。
路由事件處理常式委派提供對兩個物件的參考︰引發事件的物件,以及已叫用處理常式的物件。 已叫用處理常式的物件是 sender
參數所報告的物件。 事件第一次引發的物件是由事件數據中的 Source 屬性所報告。 路由事件仍然可以由相同的對象引發和處理,在此情況下, sender
和 Source 相同(這是事件處理範例清單中的步驟 3 和 4 的情況)。
由於通道和反升,父元素會接收輸入事件,其中 Source 為其其中一個子元素。 當知道來源元素是什麼很重要時,您可以存取 Source 屬性來識別來源元素。
通常,一旦輸入事件標示為 Handled,就不會叫用進一步的處理程式。 一般而言,您應該在叫用處理常式來處理代表輸入事件意義之應用程式特定的邏輯處理之後,儘速將輸入事件標示為已處理。
這個關於 Handled 狀態陳述的例外是,輸入事件處理程式以刻意忽略事件數據 Handled 狀態而被註冊,將會將喚醒其他路由。 如需詳細資訊,請參閱預覽事件或將路由事件標記為已處理以及類別處理。
通道事件與事件反昇事件之間共用的事件資料模型,以及後續引發的第一個通道事件,然後是事件反昇事件,不是一般適用於所有路由事件的概念。 WPF 輸入裝置選擇如何引發和連接輸入事件組,特別實作該行為。 實作您自己的輸入事件是一個進階案例,但您也可以選擇針對自己的輸入事件遵循該模型。
某些類別會選擇對特定輸入事件進行類別處理,一般的用意是重新定義特定使用者驅動的輸入事件在該控制項內所代表的意義,然後引發新的事件。 如需詳細資訊,請參閱將路由事件標記為已處理以及類別處理。
如需輸入以及在一般應用程式案例中輸入如何與事件互動的詳細資訊,請參閱輸入概觀。
EventSetters 和 EventTriggers
在樣式中,您可以使用 EventSetter,在標記中包含一些預先宣告的 XAML 事件處理語法。 套用樣式時,會將參考的處理常式加入至樣式執行個體。 您只能針對路由事件宣告 EventSetter。 以下是一個範例。 請注意,此處參考的 b1SetColor
方法位於程式碼後置檔案中。
<StackPanel
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="SDKSample.EventOvw2"
Name="dpanel2"
Initialized="PrimeHandledToo"
>
<StackPanel.Resources>
<Style TargetType="{x:Type Button}">
<EventSetter Event="Click" Handler="b1SetColor"/>
</Style>
</StackPanel.Resources>
<Button>Click me</Button>
<Button Name="ThisButton" Click="HandleThis">
Raise event, handle it, use handled=true handler to get it anyway.
</Button>
</StackPanel>
這裡取得的優點是,此樣式可能會包含大量其他資訊,這些資訊可以套用至您應用程式中的任何按鈕,而且讓 EventSetter 成為該樣式的一部分,即使在標記層級,也會促進程式代碼重複使用。 此外, EventSetter 抽象化處理程式的方法名稱,一個步驟會遠離一般應用程式和頁面標記。
另一個結合 WPF 路由事件和動畫功能的特殊語法是 EventTrigger。 與 EventSetter一樣,只有路由事件可用於 EventTrigger。 一般而言, EventTrigger 宣告為樣式的一部分,但 EventTrigger 也可以在頁面層級元素上宣告為 Triggers 集合的一部分,或在 ControlTemplate中宣告。 EventTrigger 可讓您指定每當路由事件到達其路由中宣告該事件的 EventTrigger 時,就會執行 Storyboard 。 EventTrigger 不只是處理事件,並導致它啟動現有的分鏡腳本的優點是, EventTrigger 提供對分鏡腳本及其運行時間行為的更佳控制。 如需詳細資訊,請參閱在分鏡腳本開始後使用事件觸發程式進行控制。
深入了解路由事件
本主題主要是從描述基本概念並提供如何及何時回應路由事件的觀點來討論路由事件,而路由事件已經存在於各種基底元素和控制項中。 不過,您可以在自訂類別上建立自己的路由事件以及所有必要的支援,例如特製化的事件資料類別和委派。 路由事件擁有者可以是任何類別,但路由事件必須由 UIElement 或 ContentElement 衍生類別所引發及處理,才能有用。 如需自訂事件的詳細資訊,請參閱建立自訂路由事件。