Почему событие нажатия кнопки «всплывающее визуальное дерево» не попадает в StackPanel, как говорится в статье MSDN? - PullRequest
21 голосов
/ 19 марта 2009

В статье MSDN Понимание перенаправленных событий и команд В WPF указано

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

Однако, в этом примере, когда вы нажимаете кнопку , она не «всплывает в визуальном дереве» для обработки родительским событием StackPanel , т. Е. Нажатие на кнопку не вызывает событие.

Почему бы и нет? Что они имеют в виду под "пузырением" , если не это?

XAML:

<Window x:Class="TestClickEvents456.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300">
    <StackPanel x:Name="TheStackPanel"
                Background="Yellow"
                MouseDown="TheStackPanel_MouseDown">
        <Button x:Name="TheButton"
                Margin="10"
                Content="Click This"/>
        <TextBlock x:Name="TheMessage"
                   Text="Click the button or the yellow area"/>
    </StackPanel>
</Window>

код-за:

using System.Windows;
using System.Windows.Input;

namespace TestClickEvents456
{
    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();
        }

        private void TheStackPanel_MouseDown(object sender, MouseButtonEventArgs e)
        {
            TheMessage.Text = "StackPanel was clicked.";
        }

    }
}

Ответы [ 5 ]

25 голосов
/ 19 марта 2009

Событие вспыхивает, пока не будет обработано ...

Поскольку Button что-то делает с помощью щелчков мыши, она поглощает событие мыши и превращает его в ClickEvent.

Если вы используете PreviewMouseDown, вы видите, что StackPanel сначала получает событие, а не кнопка. Для предварительного просмотра событий используется подход Tunnel down.

8 голосов
/ 19 марта 2009

Как уже говорили другие, это потому, что событие MouseDown обрабатывается Button до того, как оно может всплыть. Вы можете увидеть это в Reflector, в ButtonBase.OnMouseLeftButtonDown:

protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
{
    if (this.ClickMode != ClickMode.Hover)
    {
        e.Handled = true;
        // SNIP...
    }
    base.OnMouseLeftButtonDown(e);
}

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

Если вы делаете это где-то вместо установки обработчика MouseDown в XAML:

TheStackPanel.AddHandler(MouseDownEvent, new MouseButtonEventHandler(TheStackPanel_MouseDown), true);

Вы получите все MouseDown события на TheStackPanel, независимо от того, были ли они обработаны.

7 голосов
/ 19 марта 2009

Кроме того, если вы хотите, чтобы стековая панель получала событие, измените стековую панель xaml на:

<StackPanel x:Name="TheStackPanel" 
            Background="Yellow"
            Button.Click="TheStackPanel_MouseDown" />

и подпись события:

private void TheStackPanel_MouseDown(object sender, RoutedEventArgs e)

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

2 голосов
/ 17 января 2013

событие кнопки Подавить mousedown и mouseup, потому что событие кнопки является событием высокого уровня и имеет бит кода, который дает дескриптор флага true. Эта причина. Подавленный для mousdown, чтобы решить эту проблему, вы можете добавить этот код в конструктор окна

TheButton.AddHandler(
    UIElement.MouseDownEvent, 
    new MouseButtonEventHandler(TheStackPanel_MouseDown),
    true);
2 голосов
/ 19 марта 2009

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

Событие будет пузыриться (распространяться) вверх по визуальному дереву от исходного элемента до тех пор, пока оно не будет обработано или не достигнет корневого элемента.

EDIT:

Эдвард Тангуэй (OP) прокомментировал этот ответ, и я копирую его комментарий здесь, потому что он очень актуален:

"Я не вижу, что кнопка обрабатывает событие, т. Е. У меня нет обработчика щелчков по кнопке, у меня действительно есть обработчик щелчков (MouseDown) на StackPanel, и, следовательно, я думаю, что он будет всплывать ПРОШЛ button, так как кнопка не обрабатывает ее и обрабатывается панелью стека, которая делает это, верно? "

Вы правы. Кнопка не обрабатывает событие MouseDown, так как для этого элемента управления не указан обработчик.

Но, в таком случае, MouseDown особенный. По крайней мере, в Windows Forms он используется для инициирования действий, таких как рисование и перетаскивание, поэтому, когда элемент управления получает событие, он перехватывает все последующие сообщения мыши, даже если вы не определили для него обработчики. Эта ловушка делается, когда элемент управления устанавливает для свойства Capture значение True, и это эффективно предотвращает всплытие последующих событий. Для свойства Capture в Windows Forms возвращается значение False, когда он получает событие MouseUp.

Я повторяю, это так работает в Windows Forms, вы можете перепроверить это, но, IMHO, нет никаких причин, почему это должно отличаться для WPF.

Для справки: см. Раздел «Обработка форм Windows» по адресу http://blogs.msdn.com/jfoscoding/archive/2005/07/28/444647.aspx (немного прокрутите вниз от середины страницы).

Примечание. См. Мой комментарий к ответу Арктуру, в котором приведены ссылки на всплывающие последовательности, связанные с пузырьковыми и туннельными событиями.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...