Почему свойство Handled в PreviewMouseLeftButtonDownEvent влияет на ClickEvent?
Предположим, вы добавили обработчик ClickEvent и PreviewMouseLeftButtonDown-Button для кнопки
<Button x:Name="button"
Click="Button_Click"
PreviewMouseLeftButtonDown="Button_PreviewMouseLeftButtonDown">
</Button>
При нажатии на кнопку сначала запускается PreviewMouseLeftButtonDown, а затем событие Click.
Если вы установите e.Handled = true
в Preview...-Event, событие Click больше не обрабатывается.
Однако теперь давайте подумаем о MouseLeftButtonDownEvent.
Во-первых, стратегия маршрутизации этого события является прямой. Таким образом, это повторно поднято для каждого контроля. Напротив, Preview...- Событие туннелируется, Click-Event пузырится.
Во-вторых, добавление MouseLeftButtonDownEventHandler является успешным только при регистрации обработчика, так что он даже вызывается для уже обработанных событий, как показано в следующем фрагменте кода.
button.AddHandler(MouseLeftButtonDownEvent,
new MouseButtonEventHandler(Button_MouseLeftButtonDown),
true);
Я написал тестовое приложение с кнопкой и добавил обработчик для каждого из событий. Когда вызывается обработчик события, он записывает некоторую информацию в текстовый блок.
- Когда я нажимаю кнопку, запускаются все три обработчика событий.
- Когда я добавлю
e.Handled = true
в Preview...-EventHandler, вызывается только этот обработчик событий. Даже Мышь... - EventHandler не поднимается, хотя я поставилUIElement.AddHandler handledEventsToo
к истине. - Когда я добавлю
e.Handled = true
мыши... - EventHandler, все три обработчика событий вызываются.
Это не имеет никакого смысла для меня. Мышь...-EventHandlers не влияют на Click-EventHandlers, но Preview...-EventHandlers влияют как на Mouse...-, так и Click-EventHandlers.
И даже "заставить" обработать событие не удалось для мыши...-EventHandler.
На самом деле, я никогда не думал, что обработчики событий разных типов могут влиять друг на друга. Что я понял, так это то, что если у меня есть Preview...- Event и Click-Event, то они независимы.
Итак, что мне не хватает?
Вот довольно простой пример кода:
XAML:
<DockPanel>
<Border x:Name="border" DockPanel.Dock="Top" Height="50"
BorderBrush="Gray" BorderThickness="1">
<StackPanel x:Name="stackpanel" Background="LightGray"
Orientation="Horizontal" HorizontalAlignment="Center">
<Button x:Name="button" Width="Auto"
PreviewMouseLeftButtonDown="Button_PreviewMouseLeftButtonDown">
Click Me
</Button>
</StackPanel>
</Border>
<Border DockPanel.Dock="Bottom" BorderBrush="Gray" BorderThickness="1">
<ScrollViewer>
<TextBlock x:Name="textBlock" TextWrapping="Wrap"/>
</ScrollViewer>
</Border>
</DockPanel>
Code-Behind:
public MainWindow()
{
InitializeComponent();
button.AddHandler(MouseLeftButtonDownEvent, new MouseButtonEventHandler(Button_MouseLeftButtonDown), true);
button.AddHandler(ButtonBase.ClickEvent, new RoutedEventHandler(Button_Click), true);
stackpanel.AddHandler(ButtonBase.ClickEvent, new RoutedEventHandler(Button_Click), true /*false*/ );
}
private void Output(object sender, RoutedEventArgs e)
{
textBlock.Text += "RoutedEvent: " + e.RoutedEvent + "\n";
textBlock.Text += "Sender: " + sender + "\n";
textBlock.Text += "Source: " + e.Source + "\n";
textBlock.Text += "OriginalSource: " + e.OriginalSource + "\n" + "\n";
}
private void Button_Click(object sender, RoutedEventArgs e)
{
// e.Handled = true;
Output(sender, e);
}
private void Button_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
// e.Handled = true;
Output(sender, e);
}
private void Button_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
Output(sender, e);
}
1 ответ
Я никогда не думал, что обработчики событий разных типов могут влиять друг на друга
Вы в основном правы, так как это довольно редко, но вы можете найти свои ответы на странице предварительного просмотра событий в MSDN. Со связанной страницы:
Например, кнопка Windows Presentation Foundation (WPF) подавляет всплывающие события MouseLeftButtonDown и MouseLeftButtonDown, вызываемые кнопкой или ее составными элементами, в пользу захвата мыши и вызова события Click, которое всегда вызывается самой кнопкой. Событие и его данные все еще продолжаются по маршруту, но, поскольку Button помечает данные события как Обработанные, вызываются только обработчики для события, которые конкретно указали, что они должны действовать в случае handledEventsToo.
Кроме того, вы сказали это:
Когда я добавляю e.Handled = true в Mouse...-EventHandler, все три обработчика событий вызываются
Что ожидается, как постановка e.Handled
в обработчике всплывающих событий ничего не будет делать... ничто не будет считывать это значение после того, как событие покинуло код обработчика. e.Handled
преимущественно используется в туннельных обработчиках событий, чтобы остановить события от дальнейшей маршрутизации. Опять же со связанной страницы:
Для входных событий, в частности, события предварительного просмотра также совместно используют экземпляры данных события с эквивалентным пузырьковым событием. Если вы используете обработчик класса события Preview, чтобы отметить обработанное событие ввода, всплывающий обработчик класса события ввода не будет вызываться. Или, если вы используете обработчик экземпляра события Preview, чтобы отметить обработанное событие, обработчики для события всплывающего сообщения обычно не будут вызываться.