Button.MouseDown - PullRequest
       15

Button.MouseDown

8 голосов
/ 06 июня 2010

Я относительно новичок в WPF. Я пытаюсь понять разницу между MouseDownEvent и PreviewMouseDownEvent.

Я понимаю стратегии событий WPF и понимаю, что событие MouseDown является пузырьковым событием, а PreviewMouseDown является туннельным событием.

Я также понимаю, в каком порядке запускаются эти события - в соответствии с этим обзором MSDN http://msdn.microsoft.com/en-us/library/ms742806.aspx#routing (там есть схема с примером).

Итак, я попытался написать код для себя, проверьте это, например:

<Grid x:Name="grid" Width="250">
    <StackPanel Mouse.MouseDown="StackPanel_MouseDown" PreviewMouseDown="StackPanel_PreviewMouseDown">
    <WPFVisualizerExample:MyButton x:Name="B1" PreviewMouseDown="B1_PreviewMouseDown" MouseDown="B1_MouseDown" Margin="5,5,5,5">
            <WPFVisualizerExample:MyButton x:Name="B2" PreviewMouseDown="B2_PreviewMouseDown" MouseDown="B2_MouseDown"  Margin="5,5,5,5">
                <WPFVisualizerExample:MyButton x:Name="B3" PreviewMouseDown="B3_PreviewMouseDown" MouseDown="B3_MouseDown"  Margin="5,5,5,5">Click Me</WPFVisualizerExample:MyButton>
            </WPFVisualizerExample:MyButton>
    </WPFVisualizerExample:MyButton>           
    </StackPanel>        
</Grid>

У меня есть обработчик событий для каждого из событий (предварительный просмотр и отсутствие предварительного просмотра), и я хотел посмотреть, что происходит, какое событие выбрасывается ( У меня отображается окно сообщения для каждого события ).

Пользовательский элемент управления «MyButton» просто расширяет базовую кнопку и переопределяет OnMouseDown и OnPreviewMouseDown, чтобы установить значение e.Handled false:

    protected override void OnMouseDown(System.Windows.Input.MouseButtonEventArgs e)
    {            
        base.OnMouseDown(e);
        e.Handled = false;
    }

    protected override void OnPreviewMouseDown(System.Windows.Input.MouseButtonEventArgs e)
    {            
        base.OnPreviewMouseDown(e);
        e.Handled = false;
    }

(пробовал с этим и без этого).

Согласно обзору MSDN (по ссылке выше), если у меня есть 3 элемента, маршрут событий должен быть следующим:

PreviewMouseDown (туннель) для корневого элемента.

PreviewMouseDown (туннель) на промежуточном элементе № 1.

PreviewMouseDown (tunnel) для исходного элемента №2.

MouseDown (пузырь) на элементе # 2 источника.

MouseDown (пузырь) на промежуточном элементе № 1.

MouseDown (пузырь) на корневом элементе.

Итак, я ожидал, что окна сообщений будут отображаться в соответствии с вышеизложенным. По какой-то причине, которую я не понимаю, генерируются только события предварительного просмотра (в соответствии с тем, что MSDN говорит Preview_B1 => Preview_B2 => Preview_B3). Мои ожидания были: Preview_B1 => Preview_B2 => Preview_B3 => NonPreview_B3 => NonPreview_B2 => NonPreview_B1.

Но события без предварительного просмотра вообще не генерируются.

Так что в принципе я не понимаю маршрут событий, из обзора MSDN я понял, что маршрут начинается от корневого элемента, идет вниз (туннель) к исходному элементу, а затем обратно вверх (пузырь) к корневому элементу , но это не то, что происходит на практике.

Мне действительно важно понять, как работают эти события, я, наверное, не понимаю чего-то простого здесь, ваша помощь будет оценена.

!! СПАСИБО -Gili

Ответы [ 4 ]

7 голосов
/ 06 июня 2010

Поскольку функция элемента управления Button заключается в создании события Click (или запуска команды), он обрабатывает события мыши немного по-другому, чем другие элементы управления. Когда Button получает событие PreviewMouseDown, оно преобразует его в событие Click, отменяя любое дальнейшее туннелирование Preview и события пузыря MouseDown. В этом есть некоторые различия в зависимости от настройки ClickMode кнопки. Если вы предпочитаете использовать события мыши сами, вы можете вместо этого просто использовать ContentControl (попробуйте, и вы увидите, что именно вы ожидаете), но вы, вероятно, обнаружите, что в большинстве случаев гораздо проще использовать Button.Click.

UPDATE

В вашем коде должно происходить что-то еще, что приводит к остановке маршрутизации событий. Вот пример, аналогичный вашему, который я проверил и который показывает ожидаемый результат (некоторые стили добавлены, чтобы элементы были очевидны):

<Window.Resources>
    <Style TargetType="{x:Type ContentControl}">
        <Setter Property="BorderThickness" Value="5" />
        <Setter Property="Padding" Value="10" />
        <Setter Property="Background" Value="PaleGreen" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type ContentControl}">
                    <Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Padding="{TemplateBinding Padding}">
                        <ContentPresenter/>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</Window.Resources>

<StackPanel Tag="Panel" PreviewMouseDown="PreviewMouseDown" MouseDown="MouseDown">
    <ContentControl BorderBrush="Red" Tag="C1" PreviewMouseDown="PreviewMouseDown" MouseDown="MouseDown">
        <ContentControl BorderBrush="Green" Tag="C2" PreviewMouseDown="PreviewMouseDown" MouseDown="MouseDown">
            <ContentControl Content="Click Me" BorderBrush="Blue" Tag="C3" PreviewMouseDown="PreviewMouseDown" MouseDown="MouseDown"/>
        </ContentControl>
    </ContentControl>
</StackPanel>

и простые обработчики для записи в Debug:

private void PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
    Debug.WriteLine((sender as FrameworkElement).Tag + " Preview");
}

private void MouseDown(object sender, MouseButtonEventArgs e)
{
    Debug.WriteLine((sender as FrameworkElement).Tag + " Bubble");
}

Вывод отладки (если щелкнуть текст в центре):

Панель предварительного просмотра
Предварительный просмотр C1
C2 Preview
C3 Preview
C3 Bubble
C2 Bubble
C1 Bubble
Панель Пузырь

2 голосов
/ 26 ноября 2012

В настоящее время я изучаю концепцию маршрутизируемых событий, и в моих тестовых приложениях основное различие заключается в злоупотреблении методом MessageBox.Show(). Кажется, что когда вы используете его для уведомления о вызываемых событиях, сначала возникают все события туннелирования PreviewMouseDown, и отображаются соответствующие окна сообщений, и тот факт, что они получают фокус, отменяет или обрабатывает всплывающие события MouseDown. , В данном примере кода мы можем изменить способ уведомления (например, Debug.WriteLine, как в примере с Джоном, или обновить некоторое свойство зависимости от строки, привязанное к некоторому TextBox.Text)

0 голосов
/ 28 августа 2017

Этот вопрос старый, но я работаю в той же области, и у меня может быть ответ. У Джона Боуэна с этим не было проблем. Он тестировал с помощью инструкций трассировки отладки. Те, у кого проблемы с этим, тестируют с использованием MessageBoxes.

И вот в чем проблема: нажатие кнопки мыши устанавливает фокус и захватывает мышь. Но если вы отобразите MessageBox, он украдет фокус и захват мыши. В этот момент кнопка действительно сбита с толку, потому что мышь нажата, но на ней нет захвата или фокуса. После этого вы не ожидаете нормальной последовательности сообщений мыши. Мышь забрана!

0 голосов
/ 18 февраля 2013

Аматсу прав! У меня была точно такая же проблема. Я создал кнопку и зарегистрировал MouseDown и PreviewMouseDown-Event. В обработчике событий я только что отобразил окно сообщения для целей отладки. Мне всегда было интересно, почему я просто получаю PreviewMouseDown-Event, а не MouseDown-Event. Причиной был MessageBox. Поэтому я изменил MessageBox на System.Diagnostic.WriteLine и все работало нормально:)

Спасибо!

...