代码之家  ›  专栏  ›  技术社区  ›  Edward Tanguay

为什么在msdn文章中不单击事件“冒泡可视化树”到stackpanel?

  •  21
  • Edward Tanguay  · 技术社区  · 16 年前

    在msdn文章中 Understanding Routed Events and Commands In 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 回复  |  直到 6 年前
        1
  •  25
  •   eoinmullan    9 年前

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

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

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

        2
  •  8
  •   Robert Macnee    16 年前

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

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

    一种解决方案是 事件 事件,并指示您不关心事件是否被处理。你可以用 AddHandler 方法。它有一个布尔重载,允许您监听已经处理的事件。

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

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

    你会收到所有 事件 事件对 TheStackPanel 不管他们是否被处理过。

        3
  •  7
  •   Razzie    16 年前

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

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

    活动签名:

    private void TheStackPanel_MouseDown(object sender, RoutedEventArgs e)
    

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

        4
  •  2
  •   vmarquez    16 年前

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

    事件将从源元素向上冒泡(传播)可视化树。 直到处理完为止 或者到达根元素。

    编辑:

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

    “我看不到按钮正在处理事件,也就是说,按钮上没有单击处理程序,stackpanel上有单击处理程序(mousedown),因此我认为按钮会冒泡过去,因为按钮不处理它,由stackpanel来处理,对吗?”

    你是对的。按钮未处理MouseDown事件,因为在该控件上没有为其指定处理程序ha。

    但是,老鼠镇在某种程度上是特别的。至少在Windows窗体中,它用于启动绘图和拖动操作,因此当控件获取事件时,它将继续捕获所有后续鼠标消息,即使您没有为其定义处理程序。当控件将Capture属性设置为true时,就会执行此陷阱,这样可以有效地阻止后续事件冒泡。当获取mouseup事件时,Windows窗体会将Capture属性设置回false。

    我重复一遍,这就是它在Windows窗体中的工作方式,您可能需要再次检查这个,但是,imho没有任何理由说明WPF的情况应该有所不同。

    参考:请参阅“Windows窗体处理”部分 http://blogs.msdn.com/jfoscoding/archive/2005/07/28/444647.aspx (从页面中间稍微向下滚动)。

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

        5
  •  2
  •   Craig    8 年前

    button事件禁止mousedown和mouseup,因为button事件是高级事件,并且有一些代码赋予flag handle true。为了解决此问题,禁止mousedown。可以将此代码添加到window的构造函数中。

    TheButton.AddHandler(
        UIElement.MouseDownEvent, 
        new MouseButtonEventHandler(TheStackPanel_MouseDown),
        true);
    
    推荐文章