- WPF 教程
- WPF - 首頁
- WPF - 概述
- WPF - 環境設定
- WPF - Hello World
- WPF - XAML 概述
- WPF - 元素樹
- WPF - 依賴屬性
- WPF - 路由事件
- WPF - 控制元件
- WPF - 佈局
- WPF - 佈局巢狀
- WPF - 輸入
- WPF - 命令列
- WPF - 資料繫結
- WPF - 資源
- WPF - 模板
- WPF - 樣式
- WPF - 觸發器
- WPF - 除錯
- WPF - 自定義控制元件
- WPF - 異常處理
- WPF - 本地化
- WPF - 互動
- WPF - 2D 圖形
- WPF - 3D 圖形
- WPF - 多媒體
- WPF 有用資源
- WPF - 快速指南
- WPF - 有用資源
- WPF - 討論
WPF - 路由事件
路由事件是一種事件型別,它可以在元素樹中的多個偵聽器上呼叫處理程式,而不僅僅是引發該事件的物件。它基本上是由 Routed Event 類例項支援的 CLR 事件。它在 WPF 事件系統中註冊。路由事件有三種主要的路由策略,如下所示:
- 直接事件
- 冒泡事件
- 隧道事件
直接事件
直接事件類似於 Windows 窗體中的事件,這些事件由事件起源的元素引發。
與標準 CLR 事件不同,直接路由事件支援類處理,並且可以在自定義控制元件樣式中的事件設定器和事件觸發器中使用。
滑鼠進入事件就是一個直接事件的很好的例子。
冒泡事件
冒泡事件從事件起源的元素開始。然後它沿著視覺化樹向上傳播到視覺化樹中最頂層的元素。因此,在 WPF 中,最頂層的元素很可能是一個視窗。
隧道事件
呼叫元素樹根上的事件處理程式,然後事件沿著視覺化樹向下傳播到所有子節點,直到到達事件起源的元素。
冒泡事件和隧道事件的區別在於,隧道事件總是以預覽開始。
在 WPF 應用程式中,事件通常實現為隧道/冒泡對。因此,您將有一個 PreviewMouseDown 事件,然後是一個 MouseDown 事件。
下面是一個路由事件的簡單示例,其中建立了一個按鈕和三個文字塊,並設定了一些屬性和事件。
<Window x:Class = "WPFRoutedEvents.MainWindow"
xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"
Title = "MainWindow" Height = "450" Width = "604" ButtonBase.Click = "Window_Click" >
<Grid>
<StackPanel Margin = "20" ButtonBase.Click = "StackPanel_Click">
<StackPanel Margin = "10">
<TextBlock Name = "txt1" FontSize = "18" Margin = "5" Text = "This is a TextBlock 1" />
<TextBlock Name = "txt2" FontSize = "18" Margin = "5" Text = "This is a TextBlock 2" />
<TextBlock Name = "txt3" FontSize = "18" Margin = "5" Text = "This is a TextBlock 3" />
</StackPanel>
<Button Margin = "10" Content = "Click me" Click = "Button_Click" Width = "80"/>
</StackPanel>
</Grid>
</Window>
以下是按鈕、StackPanel 和視窗的 Click 事件實現的 C# 程式碼。
using System.Windows;
namespace WPFRoutedEvents {
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window {
public MainWindow() {
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e) {
txt1.Text = "Button is Clicked";
}
private void StackPanel_Click(object sender, RoutedEventArgs e) {
txt2.Text = "Click event is bubbled to Stack Panel";
}
private void Window_Click(object sender, RoutedEventArgs e) {
txt3.Text = "Click event is bubbled to Window";
}
}
}
編譯並執行上述程式碼後,將生成以下視窗:
單擊按鈕時,文字塊將更新,如下所示。
如果要在任何特定級別停止路由事件,則需要設定 e.Handled = true;
讓我們更改StackPanel_Click事件,如下所示:
private void StackPanel_Click(object sender, RoutedEventArgs e) {
txt2.Text = "Click event is bubbled to Stack Panel";
e.Handled = true;
}
單擊按鈕時,您會注意到單擊事件不會路由到視窗,而會在 stackpanel 處停止,並且第 3 個文字塊不會更新。
自定義路由事件
在 .NET 框架中,也可以定義自定義路由事件。您需要按照以下步驟在 C# 中定義自定義路由事件。
使用系統呼叫 RegisterRoutedEvent 宣告並註冊您的路由事件。
指定路由策略,即冒泡、隧道或直接。
提供事件處理程式。
讓我們舉一個例子來更深入地瞭解自定義路由事件。請按照以下步驟操作:
使用 WPFCustomRoutedEvent 建立一個新的 WPF 專案
右鍵單擊您的解決方案,然後選擇新增 > 新建項...
將開啟以下對話方塊,現在選擇自定義控制元件 (WPF) 並將其命名為MyCustomControl。
單擊新增按鈕,您將看到兩個新檔案 (Themes/Generic.xaml 和 MyCustomControl.cs) 將新增到您的解決方案中。
以下 XAML 程式碼在 Generic.xaml 檔案中設定自定義控制元件的樣式。
<ResourceDictionary
xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local = "clr-namespace:WPFCustomRoutedEvent">
<Style TargetType = "{x:Type local:MyCustomControl}">
<Setter Property = "Margin" Value = "50"/>
<Setter Property = "Template">
<Setter.Value>
<ControlTemplate TargetType = "{x:Type local:MyCustomControl}">
<Border Background = "{TemplateBinding Background}"
BorderBrush = "{TemplateBinding BorderBrush}"
BorderThickness = "{TemplateBinding BorderThickness}">
<Button x:Name = "PART_Button" Content = "Click Me" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
以下是MyCustomControl 類的 C# 程式碼,該類繼承自Control 類,其中為自定義控制元件建立了一個自定義路由事件 Click。
using System.Windows;
using System.Windows.Controls;
namespace WPFCustomRoutedEvent {
public class MyCustomControl : Control {
static MyCustomControl() {
DefaultStyleKeyProperty.OverrideMetadata(typeof(MyCustomControl),
new FrameworkPropertyMetadata(typeof(MyCustomControl)));
}
public override void OnApplyTemplate() {
base.OnApplyTemplate();
//demo purpose only, check for previous instances and remove the handler first
var button = GetTemplateChild("PART_Button") as Button;
if (button ! = null)
button.Click + = Button_Click;
}
void Button_Click(object sender, RoutedEventArgs e) {
RaiseClickEvent();
}
public static readonly RoutedEvent ClickEvent =
EventManager.RegisterRoutedEvent("Click", RoutingStrategy.Bubble,
typeof(RoutedEventHandler), typeof(MyCustomControl));
public event RoutedEventHandler Click {
add { AddHandler(ClickEvent, value); }
remove { RemoveHandler(ClickEvent, value); }
}
protected virtual void RaiseClickEvent() {
RoutedEventArgs args = new RoutedEventArgs(MyCustomControl.ClickEvent);
RaiseEvent(args);
}
}
}
以下是 C# 中的自定義路由事件實現,當用戶單擊它時,它將顯示一個訊息框。
using System.Windows;
namespace WPFCustomRoutedEvent {
// <summary>
// Interaction logic for MainWindow.xaml
// </summary>
public partial class MainWindow : Window {
public MainWindow() {
InitializeComponent();
}
private void MyCustomControl_Click(object sender, RoutedEventArgs e) {
MessageBox.Show("It is the custom routed event of your custom control");
}
}
}
以下是 MainWindow.xaml 中的實現,用於新增具有路由事件 Click 的自定義控制元件。
<Window x:Class = "WPFCustomRoutedEvent.MainWindow"
xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local = "clr-namespace:WPFCustomRoutedEvent"
Title = "MainWindow" Height = "350" Width = "604">
<Grid>
<local:MyCustomControl Click = "MyCustomControl_Click" />
</Grid>
</Window>
編譯並執行上述程式碼後,將生成以下視窗,其中包含一個自定義控制元件。
當您單擊自定義控制元件時,它將生成以下訊息。