Почему событие нажатия кнопки "всплывающее визуальное дерево" не попадает в StackPanel, как говорится в статье MSDN?
В статье 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 ответов
Событие вспыхивает, пока не будет обработано...
Поскольку Button что-то делает с помощью щелчков мышью, она поглощает событие мыши и превращает его в ClickEvent.
Если вы используете PreviewMouseDown, вы увидите, что StackPanel сначала получает событие, а не кнопку. Для предварительного просмотра событий используется подход Tunnel down.
Как уже говорили другие, это потому, что 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
независимо от того, были ли они обработаны.
Кроме того, если вы хотите, чтобы стековая панель получала событие, измените стековую панель xaml на:
<StackPanel x:Name="TheStackPanel"
Background="Yellow"
Button.Click="TheStackPanel_MouseDown" />
и подпись события для:
private void TheStackPanel_MouseDown(object sender, RoutedEventArgs e)
В этом случае стековая панель получит событие нажатия кнопки. Однако нажатие на саму панель стека не вызовет какого-либо события, так как оно специально слушает нажатие кнопки.
Событие кнопки Подавить mousedown и mouseup, потому что событие кнопки является событием высокого уровня и имеет бит кода, который дает дескриптор флага true. Эта причина Подавлена для mousdown, чтобы решить эту проблему, вы можете добавить этот код в конструктор окна
TheButton.AddHandler(
UIElement.MouseDownEvent,
new MouseButtonEventHandler(TheStackPanel_MouseDown),
true);
Это происходит потому, что все сообщения обрабатываются Button, и сообщения останавливают, сообщение перестает пузыриться там. Ответ прямо в тексте вашего вопроса:
Событие будет пузыриться (распространяться) вверх по визуальному дереву от исходного элемента до тех пор, пока оно не будет обработано или не достигнет корневого элемента.
РЕДАКТИРОВАТЬ:
Эдвард Тангей (OP) прокомментировал этот ответ, и я копирую его комментарий здесь, потому что он очень актуален:
"Я не вижу, что кнопка обрабатывает событие, т. Е. У меня нет обработчика щелчков по кнопке, у меня действительно есть обработчик щелчков (MouseDown) на StackPanel, и, следовательно, я бы подумал, что она будет вставлять кнопку PAST, так как Кнопка не справляется с этим и обрабатывается стековой панелью, верно?"
Вы правы. Кнопка не обрабатывает событие 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 (прокрутите немного вниз от середины страницы).
Примечание. См. Мой комментарий к ответу Арктуру, в котором приведена ссылка на последовательности всплывающих событий, связанных с пузырьками и туннелями.