WPF - перенаправленные события
А routed event- это тип события, который может вызывать обработчики для нескольких прослушивателей в дереве элементов, а не только для объекта, вызвавшего событие. По сути, это событие CLR, поддерживаемое экземпляром класса Routed Event. Он зарегистрирован в системе событий WPF. RoutedEvents имеет три основных стратегии маршрутизации, а именно:
- Прямое событие
- Бурлящее событие
- Туннельное событие
Прямое событие
Прямое событие похоже на события в формах Windows, которые инициируются элементом, в котором возникло событие.
В отличие от стандартного события CLR, события с прямой маршрутизацией поддерживают обработку классов, и их можно использовать в установщиках событий и триггерах событий в рамках вашего стиля пользовательского элемента управления.
Хорошим примером прямого события может служить событие MouseEnter.
Бурлящее событие
Событие восходящей цепочки начинается с элемента, из которого возникло событие. Затем он перемещается вверх по визуальному дереву к самому верхнему элементу визуального дерева. Итак, в WPF самым верхним элементом, скорее всего, является окно.
Туннельное событие
Вызываются обработчики событий в корне дерева элементов, а затем событие перемещается вниз по визуальному дереву ко всем дочерним узлам, пока не достигнет элемента, в котором возникло событие.
Разница между восходящим потоком и событием туннелирования заключается в том, что событие туннелирования всегда начинается с предварительного просмотра.
В приложении WPF события часто реализуются как пара туннелирования / восходящей маршрутизации. Итак, у вас будет предварительный просмотр MouseDown, а затем событие 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>
Вот код C # для реализации событий Click для Button, StackPanel и 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";
}
}
}
Когда вы скомпилируете и выполните приведенный выше код, он выдаст следующее окно:
Когда вы нажимаете на кнопку, текстовые блоки обновляются, как показано ниже.
Если вы хотите остановить перенаправленное событие на каком-либо конкретном уровне, вам необходимо установить 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;
}
Когда вы щелкнете по кнопке, вы увидите, что событие щелчка не будет перенаправлено в окно и остановится на панели стека, а 3- й текстовый блок не будет обновлен.
Настраиваемые перенаправленные события
В .NET framework также можно определить настраиваемое перенаправленное событие. Чтобы определить настраиваемое перенаправленное событие в C #, необходимо выполнить следующие действия.
Объявите и зарегистрируйте перенаправленное событие с помощью системного вызова RegisterRoutedEvent.
Укажите стратегию маршрутизации, т. Е. Пузырьковую, туннельную или прямую.
Предоставьте обработчик событий.
Давайте рассмотрим пример, чтобы понять больше о настраиваемых перенаправленных событиях. Следуйте инструкциям ниже -
Создайте новый проект WPF с WPFCustomRoutedEvent
Щелкните правой кнопкой мыши свое решение и выберите Добавить> Новый элемент ...
Откроется следующий диалог, теперь выберите Custom Control (WPF) и назови это MyCustomControl.
Щелкните значок Add кнопку, и вы увидите, что в ваше решение будут добавлены два новых файла (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>
Ниже приведен код C # для MyCustomControl class который наследуется от Control class в котором создается настраиваемое перенаправленное событие 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>
Когда приведенный выше код компилируется и выполняется, он создает следующее окно, содержащее настраиваемый элемент управления.
При нажатии на настраиваемый элемент управления появится следующее сообщение.