WPF - Sự kiện được định tuyến
A routed eventlà một loại sự kiện có thể gọi các trình xử lý trên nhiều trình nghe trong một cây phần tử thay vì chỉ đối tượng đã tạo ra sự kiện. Về cơ bản, nó là một sự kiện CLR được hỗ trợ bởi một thể hiện của lớp Sự kiện định tuyến. Nó được đăng ký với hệ thống sự kiện WPF. RoutedEvents có ba chiến lược định tuyến chính như sau:
- Sự kiện trực tiếp
- Sự kiện bong bóng
- Sự kiện đường hầm
Sự kiện trực tiếp
Một sự kiện trực tiếp tương tự như các sự kiện trong biểu mẫu Windows được nâng lên bởi phần tử mà sự kiện được tạo ra.
Không giống như sự kiện CLR tiêu chuẩn, các sự kiện được định tuyến trực tiếp hỗ trợ xử lý lớp và chúng có thể được sử dụng trong Bộ thiết lập sự kiện và Trình kích hoạt sự kiện theo kiểu Kiểm soát tùy chỉnh của bạn.
Một ví dụ điển hình về sự kiện trực tiếp sẽ là sự kiện MouseEnter.
Sự kiện bong bóng
Một sự kiện sôi sục bắt đầu với phần tử nơi bắt nguồn sự kiện. Sau đó, nó di chuyển lên cây trực quan đến phần tử trên cùng trong cây trực quan. Vì vậy, trong WPF, phần tử trên cùng rất có thể là một cửa sổ.
Sự kiện đường hầm
Các trình xử lý sự kiện trên gốc cây phần tử được gọi và sau đó sự kiện di chuyển xuống cây trực quan đến tất cả các nút con cho đến khi nó đến phần tử mà sự kiện bắt nguồn.
Sự khác biệt giữa sự kiện sủi bọt và sự kiện đào hầm là sự kiện đào đường hầm sẽ luôn bắt đầu bằng bản xem trước.
Trong một ứng dụng WPF, các sự kiện thường được triển khai dưới dạng một cặp tạo đường hầm / sủi bọt. Vì vậy, bạn sẽ có một MouseDown xem trước và sau đó là một sự kiện MouseDown.
Dưới đây là một ví dụ đơn giản về sự kiện Định tuyến trong đó một nút và ba khối văn bản được tạo với một số thuộc tính và sự kiện.
<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>
Đây là mã C # để triển khai sự kiện Click cho Button, StackPanel và Window.
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";
}
}
}
Khi bạn biên dịch và thực thi đoạn mã trên, nó sẽ tạo ra cửa sổ sau:
Khi bạn nhấp vào nút, các khối văn bản sẽ được cập nhật, như hình dưới đây.
Nếu bạn muốn dừng sự kiện được định tuyến ở bất kỳ cấp độ cụ thể nào, thì bạn sẽ cần đặt e.Handled = true;
Hãy thay đổi StackPanel_Click sự kiện như hình dưới đây -
private void StackPanel_Click(object sender, RoutedEventArgs e) {
txt2.Text = "Click event is bubbled to Stack Panel";
e.Handled = true;
}
Khi bạn nhấp vào nút, bạn sẽ quan sát thấy sự kiện nhấp sẽ không được chuyển đến cửa sổ và sẽ dừng lại ở bảng điều khiển và khối văn bản thứ 3 sẽ không được cập nhật.
Sự kiện được định tuyến tùy chỉnh
Trong .NET framework, sự kiện được định tuyến tùy chỉnh cũng có thể được xác định. Bạn cần làm theo các bước dưới đây để xác định sự kiện được định tuyến tùy chỉnh trong C #.
Khai báo và đăng ký sự kiện được định tuyến của bạn với lệnh gọi hệ thống RegisterRoutedEvent.
Chỉ định Chiến lược định tuyến, tức là Bong bóng, Đường hầm hoặc Trực tiếp.
Cung cấp trình xử lý sự kiện.
Hãy lấy một ví dụ để hiểu thêm về các sự kiện được định tuyến tùy chỉnh. Làm theo các bước dưới đây -
Tạo một dự án WPF mới với WPFCustomRoutedEvent
Nhấp chuột phải vào giải pháp của bạn và chọn Thêm> Mục mới ...
Hộp thoại sau sẽ mở ra, bây giờ hãy chọn Custom Control (WPF) và đặt tên cho nó MyCustomControl.
Nhấn vào Add và bạn sẽ thấy rằng hai tệp mới (Themes / Generic.xaml và MyCustomControl.cs) sẽ được thêm vào giải pháp của bạn.
Mã XAML sau đây đặt kiểu cho điều khiển tùy chỉnh trong tệp 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>
Dưới đây là mã C # cho MyCustomControl class kế thừa từ Control class trong đó sự kiện được định tuyến tùy chỉnh Nhấp chuột được tạo cho điều khiển tùy chỉnh.
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);
}
}
}
Đây là triển khai sự kiện được định tuyến tùy chỉnh trong C # sẽ hiển thị một hộp thông báo khi người dùng nhấp vào nó.
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");
}
}
}
Đây là cách triển khai trong MainWindow.xaml để thêm điều khiển tùy chỉnh với sự kiện được định tuyến Nhấp chuột.
<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>
Khi đoạn mã trên được biên dịch và thực thi, nó sẽ tạo ra cửa sổ sau chứa điều khiển tùy chỉnh.
Khi bạn nhấp vào điều khiển tùy chỉnh, nó sẽ tạo ra thông báo sau.