为什么按钮单击事件“冒泡视觉树”不发生? 正如 MSDN 文章所述,到 StackPanel 了吗?

发布于 2024-07-15 12:03:20 字数 1465 浏览 10 评论 0原文

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

    }
}

In the MSDN article Understanding Routed Events and Commands In WPF, it states

an event will bubble (propagate) up the visual tree from the source element until either it has been handled or it reaches the root element.

However, in this example, when you click the button, it doesn't "bubble up the visual tree" to get handled by the parent StackPanel event, i.e. clicking on the button fires no event.

Why not? What do they mean then by "bubbling up" if not this?

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>

code-behind:

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

    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

暮光沉寂 2024-07-22 12:03:20

该事件会冒泡,直到它被处理...

由于 Button 通过您的鼠标单击执行某些操作,因此它会吸收您的鼠标事件并将其转换为 ClickEvent。

如果您使用 PreviewMouseDown,您会看到 StackPanel 在按钮之前首先接收到事件。预览事件使用 Tunnel down 方法。

The event bubbles up, until it gets handled...

Since the Button does something with your mouse clicks, it absorbs your mouse event and turns it into a ClickEvent.

If you use the PreviewMouseDown, you see that the StackPanel first receives the event before the button does.. Preview events use the Tunnel down approach..

烟花易冷人易散 2024-07-22 12:03:20

正如其他人所说,这是因为 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 方法来执行此操作。 它有一个布尔重载,可让您侦听已处理的事件。

如果您在某处执行此操作而不是在 XAML 中设置 MouseDown 处理程序:

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

您将收到 TheStackPanel 上的所有 MouseDown 事件,无论它们是否已被处理。

As others have said, it's because the MouseDown event gets handled by the Button before it can be bubbled further. You can see this in Reflector, in ButtonBase.OnMouseLeftButtonDown:

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

One solution is to listen for a MouseDown event, and indicate that you don't care if the event is handled. You can do this with the AddHandler method. It has a boolean overload that lets you listen for events which are already handled.

If you do this somewhere instead of setting the MouseDown handler in XAML:

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

You'll receive all MouseDown events on TheStackPanel, regardless of whether they've been handled.

朕就是辣么酷 2024-07-22 12:03:20

另外,如果希望stackpanel接收事件,请将stackpanel xaml更改为:

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

并将事件签名更改为:

private void TheStackPanel_MouseDown(object sender, RoutedEventArgs e)

在这种情况下,stackpanel将接收按钮的单击事件。 但是,单击堆栈面板本身不会触发任何事件,因为它专门监听按钮单击。

In addition, if you want the stackpanel to receive the event, change the stackpanel xaml to:

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

and the event signature to:

private void TheStackPanel_MouseDown(object sender, RoutedEventArgs e)

In this case, the stackpanel will recieve the button's click event. However, clicking on the stackpanel itself won't fire any event, since it listens specifically to a button click.

塔塔猫 2024-07-22 12:03:20

这是因为所有消息都被 Button 捕获处理并且消息停止消息停止在那里冒泡。 答案就在您的问题文本中:

事件将从源元素开始在视觉树中向上冒泡(传播)直到它已被处理或到达根元素。

编辑:

Edward Tanguay(OP)评论了这个答案,我在这里复制他的评论,因为它非常相关:

“我没有看到按钮正在处理该事件,即按钮上没有单击处理程序,我在 StackPanel 上有一个单击处理程序(MouseDown),因此我认为它会冒泡过去按钮,因为按钮不处理它并由堆栈面板处理,对吧?”

你是对的。 Button 未处理 MouseDown 事件,因为该控件上未为其指定处理程序。

但是,MouseDown 在某些方面是特殊的。 至少在 Windows 窗体中,它用于启动绘图和拖动等操作,因此,当控件获取事件时,即使您没有为其定义处理程序,它也会继续捕获所有后续鼠标消息。 当控件将 Capture 属性设置为 True 时,就会完成此陷阱,这有效地阻止了后续事件的冒泡。 当 Windows 窗体获取 MouseUp 事件时,Capture 属性将设置回 False。

我再说一遍,这是它在 Windows 窗体中的工作方式,您可能需要仔细检查这一点,但是,恕我直言,这对于 WPF 来说没有理由不同。

供参考:请参阅 http: //blogs.msdn.com/jfoscoding/archive/2005/07/28/444647.aspx(从页面中间稍微向下滚动)。

注意:请参阅我对 Arcturu 答案的评论,以获取有关气泡和隧道事件引发序列的参考。

It is because all the messages are being captured handled by Button and messages stop the message stops bubbling there. The answer is right in your question's text:

An event will bubble (propagate) up the visual tree from the source element until either it has been handled or it reaches the root element.

EDIT:

Edward Tanguay (OP) commented on this answer and I am copying his comment here because it is very relevant:

"I don't see that the button IS handling the event, i.e. I have no click handler on the button, I DO have a click handler (MouseDown) on the StackPanel and hence I would think it would bubble up PAST the button since the button doesn't handle it and get handled by the stackpanel which does, right?"

You are right. Button is not handling the MouseDown event because no handler ha been specified for it at that control.

But, then, MouseDown is particular in some way. At least in Windows Forms it is used to initiate actions as drawing and dragging so, when a control gets the event, it proceeds to trap all the subsequent mouse messages even if you have not defined handlers for it. This trap is done when the control sets Capture property to True and this effectively stop subsequent events from being bubbled up. Capture property is set back to False by Windows Forms when it gets a MouseUp event.

I repeat, this is the way it works in Windows Forms, you may want to double-check this but, IMHO there is no reason why this should be different for WPF.

For reference: Se the section "Windows Forms processing" at http://blogs.msdn.com/jfoscoding/archive/2005/07/28/444647.aspx (scroll slightly down from the middle of the page).

Note: See my comment to Arcturu's answer for a reference on bubble and tunneling events raise sequences.

挽袖吟 2024-07-22 12:03:20

按钮事件抑制 mousedown 和 mouseup 因为按钮事件是高级事件并且有一些代码使标志句柄为 true 这导致抑制 mousedown 来解决此问题您可以在窗口的构造函数中添加此代码

TheButton.AddHandler(
    UIElement.MouseDownEvent, 
    new MouseButtonEventHandler(TheStackPanel_MouseDown),
    true);

button event Suppress the mousedown and mouseup because button event is high level event and have bit of code that give flag handle true this cause Suppressed for mousdown to resolve this problem you can add this code in constructor of window

TheButton.AddHandler(
    UIElement.MouseDownEvent, 
    new MouseButtonEventHandler(TheStackPanel_MouseDown),
    true);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文