为何不如Msdn文章所述,为什么按钮不单击事件“泡泡视觉树”?

StackOverflow https://stackoverflow.com/questions/662201

  •  20-08-2019
  •  | 
  •  

在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.";
        }

    }
}
有帮助吗?

解决方案

活动起泡,直到处理...

由于该按钮可以通过单击鼠标进行操作,因此它会吸收鼠标事件,并将其变成clickevent。

如果您使用PreviewMousedown,您会发现StackPanel首先在按钮之前接收事件。预览事件使用隧道下的方法。

其他提示

正如其他人所说的,这是因为 MouseDown 事件由 Button 在它可以进一步冒泡之前。您可以在反射器中看到这一点,在 ButtonBase.OnMouseLeftButtonDown:

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

一种解决方案是听 MouseDown 事件,并表明您不在乎是否处理活动。你可以用 AddHandler 方法。它具有布尔人的超负荷,可让您聆听已经处理的事件。

如果您在某个地方执行此操作,而不是在XAML中设置Mousedown处理程序:

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

您将收到全部 MouseDown 事件开启 TheStackPanel, ,不管他们是否被处理。

此外,如果您希望StackPanel收到活动,请将StackPanel XAML更改为:

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

以及活动签名为:

private void TheStackPanel_MouseDown(object sender, RoutedEventArgs e)

在这种情况下,StackPanel将收到按钮的点击事件。但是,单击StackPanel本身不会发射任何事件,因为它专门听到按钮单击。

这是因为所有消息都被捕获 处理 按按钮和消息停止 消息停止 在那里冒泡。答案在您的问题文本中是正确的:

事件会从源元素中泡泡(传播)视觉树 直到处理要么 或者它到达根部元素。

编辑:

爱德华·坦格(Edward Tanguay)(OP)对此答案发表了评论,我在这里复制他的评论,因为这非常相关:

“我看不到按钮正在处理事件,即我在按钮上没有单击处理程序,我确实在stackpanel上有一个click Chandler(Mousedown),因此我认为它会在按钮上弹起,因为按钮不处理它,并由Stackpanel处理,对吗?”

你说的对。按钮没有处理Mousedown事件,因为在该控件下没有为其指定处理程序HA。

但是,然后,Mousedown在某种程度上是特别的。至少在Windows表单中,它用于启动操作作为绘图和拖动,因此,当控件获得事件时,即使您没有为其定义处理程序,它也会捕获所有后续鼠标消息。当控件将捕获属性设置为True时,该陷阱是完成此陷阱的,并且这有效阻止后续事件被冒泡。捕获属性将在获取鼠标UP事件时通过Windows表单设置为False。

我重复一遍,这是它在Windows表单中的工作方式,您可能需要仔细检查一下,但是,恕我直言,没有理由为什么WPF应该有所不同。

参考:SE节“ Windows表单处理”部分AT http://blogs.msdn.com/jfoscoding/archive/2005/07/28/4444647.aspx (从页面中间稍微向下滚动)。

注意:有关泡泡和隧道事件的参考,请参阅我对Arcturu的答案的评论。

按钮事件抑制了Mousedown和MouseUp,因为按钮事件是高级别事件,并且有一些代码,可以为true提供true此原因以解决此问题,您可以在窗口的构造函数中添加此代码

TheButton.AddHandler(
    UIElement.MouseDownEvent, 
    new MouseButtonEventHandler(TheStackPanel_MouseDown),
    true);
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top