Почему свойство Handled в PreviewMouseLeftButtonDownEvent влияет на ClickEvent?

Предположим, вы добавили ClickEvent- и PreviewMouseLeftButtonDown-Handler для кнопки

<Button x:Name="button"
    Click="Button_Click"
    PreviewMouseLeftButtonDown="Button_PreviewMouseLeftButtonDown">
</Button>

При нажатии кнопки сначала запускается PreviewMouseLeftButtonDown, затем Click-Event.

Если вы установите e.Handled = true в Preview ...- Event, Click-Event больше не будет обрабатываться.

Однако теперь давайте подумаем о MouseLeftButtonDownEvent.
Во-первых, стратегия маршрутизации этого события прямая. То есть он повторно поднимается для каждого элемента управления. Напротив, Preview ...- событие туннелируется, Click-Event всплывает.
Во-вторых, добавление MouseLeftButtonDownEventHandler является успешным только при регистрации обработчика, так что он даже вызывается для уже обработанных событий, как показано в следующий отрывок кода.

button.AddHandler(MouseLeftButtonDownEvent,
                  new MouseButtonEventHandler(Button_MouseLeftButtonDown),
                  true);

Я написал тестовое приложение с кнопкой и добавил обработчик для каждого события. Когда вызывается обработчик событий, он записывает некоторую информацию в текстовый блок.

  • Когда я нажимаю кнопку, вызываются все три обработчика событий.
  • Когда я добавляю e.Handled = true в Preview ...- EventHandler, вызывается только этот обработчик событий. Даже Mouse ... - EventHandler не вызывается, хотя я установил для UIElement.AddHandler handledEventsToo значение true.
  • Когда я добавляю e.Handled = true в Mouse ...- EventHandler, вызываются все три обработчика событий.

Для меня это не имеет никакого смысла. Mouse ...- EventHandlers не влияет на Click-EventHandlers, но Preview ...- EventHandlers влияет как на Mouse ...- и на Click-EventHandlers.
И даже «принудительная» обработка события не удалась для Mouse. ..-Обработчик события.

На самом деле, я никогда не думал, что обработчики событий разных типов могут влиять друг на друга. Я понял, что если у меня есть 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>

Код позади:

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);
}

person Em1    schedule 06.08.2014    source источник


Ответы (1)


Никогда не думал, что обработчики событий разных типов могут влиять друг на друга

В основном вы правы, так как это бывает довольно редко, но вы можете найти свои ответы в Страница предварительного просмотра событий на MSDN. Со связанной страницы:

Например, кнопка Windows Presentation Foundation (WPF) подавляет события восходящей цепочки MouseLeftButtonDown и MouseLeftButtonDown, вызываемые кнопкой или ее составными элементами, в пользу захвата мыши и возникновения события Click, которое всегда вызывается самой кнопкой. Событие и его данные по-прежнему продолжаются по маршруту, но поскольку Button помечает данные события как обработанные, вызываются только обработчики для события, в котором конкретно указано, что они должны действовать в случае handledEventsToo.

Кроме того, вы сказали это:

Когда я добавляю e.Handled = true в Mouse ...- EventHandler, вызываются все три обработчика событий.

Это ожидается, поскольку установка e.Handled в обработчике восходящего события ничего не сделает ... нет ничего, что могло бы прочитать это значение после того, как событие покинуло код обработчика. e.Handled преимущественно используется в обработчиках событий туннелирования, чтобы предотвратить дальнейшую маршрутизацию событий. Опять же, со связанной страницы:

В частности, для входных событий события предварительного просмотра также совместно используют экземпляры данных событий с эквивалентным восходящим событием. Если вы используете обработчик класса событий Preview, чтобы отметить обработанное событие ввода, обработчик класса восходящего события ввода не будет вызываться. Или, если вы используете обработчик экземпляра события Preview, чтобы отметить обработанное событие, обработчики для восходящего события обычно не вызываются.

person Sheridan    schedule 06.08.2014
comment
Означает ли это, что и Mouse, и Click являются «аналогами» Preview. Щелчок, однако, является своего рода заменой / продолжением работы Мыши? То есть предварительный просмотр влияет как на мышь, так и на щелчок, поскольку оба следят за обработанной опорой предварительного просмотра. Щелчок игнорирует обработанное состояние мыши, но не состояние предварительного просмотра. Таким образом, на щелчок влияет только предварительный просмотр, но не мышь. Кроме того, handledEventsToo влияет только на события одного типа. - Это все правильно? Если да, мне интересно, есть ли способ вызвать обработчик событий для восходящего события, даже если для события туннелирования установлено значение true? - person Em1; 06.08.2014