何时隧道和冒泡事件在WPF中有用?

时间:2013-09-04 02:48:25

标签: c# wpf mouseevent event-bubbling mousedown

我理解冒泡和隧道是如何工作的。但是,我对使用它们很困惑。 原因如下:

我想处理鼠标点击事件。要冒泡它,有MouseDown,并且为了隧道它,有PreviewMouseDown。但是,MouseDown并不一定意味着用户点击了控件。可能是用户按下按钮并离开它以取消点击。 如果没有点击按钮,我不想改变任何东西。

所以我的问题是,Bubbling / Tunneling策略有用吗?

3 个答案:

答案 0 :(得分:8)

如果列出了事件RoutedEventArgs,那么它就是路由事件。路由事件支持Bubble,Tunnel或Direct的RoutingStrategy。我们来看看Button.Click的事件处理程序:

private void Grid_Click(object sender, RoutedEventArgs e)
{
    MessageBox.Show("Button Test clicked!");
}

指定了RoutedEventArgs,因此它是路由事件。因为名称中未指定预览,所以这个泡泡事件。这可以通过以下方式证明:

<Grid ButtonBase.Click="Grid_Click">
    <Button Name="TestButton" Width="100" Height="30" Content="Test" />
</Grid>

当您点击TestButton时,事件将超过Grid,并显示一条消息:

  

单击按钮测试!

<强> Usefulness of Bubbling/Tunneling strategies

Tunneling

许多标准控件都会监听事件,例如KeyDownMouseDown等。例如 - DataGrid控件。我想按下回车键,该功能被称为添加记录。但是DataGrid已经有KeyDown个事件,因此不会引发该事件。因此,您必须在隧道事件中执行您的逻辑 - PreviewKeyDown,它将在KeyDown事件之前运行。这同样适用于RichTextBoxControl

Bubbling

有时,您需要一个特定事件的全局处理程序,因此它适用于VisualTree中的所有控件。当然,直接的事件你不能这样做。因此在舞台上出现Bubbling事件。

另一个原因是WPF的意识形态。此Button可以包含任何内容:Image,另一个Button等:

enter image description here

用户可以点击TextBlock/Image中的Button。我们如何知道点击位于Button?这是正确的,在Bubbling活动的帮助下。

有关详细信息,请参阅:

Understanding Routed Events and Commands In WPF

Edit

我改变了一点Click处理程序:

private void Grid_Click(object sender, RoutedEventArgs e)
{
    String message = "#" + eventCounter.ToString() + ":\r\n" +
            " Sender: " + sender.ToString() + ":\r\n" +
            " Source: " + e.Source + ":\r\n" +
            " Original Source: " + e.OriginalSource;

    lstEvents.Items.Add(message);
}

点击Button

的结果

enter image description here

答案 1 :(得分:3)

嗨,虽然你可以在网上获得一些好的文章,但我仍然会尝试回答这个问题。

  

假设你给一个按钮一个非常简单的外观,由一个Rectangle组成,并提供一个简单的文本作为内容即使有这样的基本视觉效果,仍然存在两个元素:文本和矩形。按钮应该响应鼠标单击鼠标是否在文本或矩形上。在标准的.NET事件处理模型中,这意味着为两个元素注册 MouseLeftButtonUp事件处理程序。

     
    

利用WPF的内容时,这个问题会变得更糟     模型。 Button不限于将纯文本作为标题 - 它可以包含任何标题     作为内容的对象。下面的xaml并不是特别雄心勃勃,但即便如此     这有六个可见元素:黄色轮廓圆圈,两个眼睛点,     嘴,文本和按钮背景本身的曲线。 附加活动     每个元素的处理程序都会很乏味和低效。要工作MouseDown我们必须在这段代码中添加8个MouseDownEvents。

  
<Button PreviewMouseDown="PreviewMouseDownButton" MouseDown="MouseDownButton">
        <Grid PreviewMouseDown="PreviewMouseDownGrid" MouseDown="MouseDownGrid">
            <Grid.ColumnDefinitions>
                <ColumnDefinition />
                <ColumnDefinition />
            </Grid.ColumnDefinitions>
            <Canvas PreviewMouseDown="PreviewMouseDownCanvas" MouseDown="MouseDownCanvas" Width="20" Height="18" VerticalAlignment="Center">
                <Ellipse PreviewMouseDown="PreviewMouseDownEllipse" MouseDown="MouseDownEllipse" x:Name="myEllipse" Canvas.Left="1" Canvas.Top="1" Width="16" Height="16" Fill="Yellow" Stroke="Black" />
                <Ellipse Canvas.Left="4.5" Canvas.Top="5" Width="2.5" MouseDown="MouseDownEllipse" Height="3" Fill="Black" />
                <Ellipse Canvas.Left="11" Canvas.Top="5" Width="2.5" MouseDown="MouseDownEllipse" Height="3" Fill="Black" />
                <Path Data="M 5,10 A 3,3 0 0 0 13,10" Stroke="Black" MouseDown="Path_MouseDown_1"/>
            </Canvas>
            <TextBlock Grid.Column="1" MouseDown="TextBlock_MouseDown_1">Click!</TextBlock>
        </Grid>
    </Button>
  
    

WPF使用RoutedEvents Bubble / Tunnel / Normal ,它比普通事件更彻底。代替     只是调用附加到引发事件的元素的处理程序,WPF走了     用户界面元素树,调用附加到路由事件的所有处理程序     从发起元素到用户界面树的根目录的任何节点。

  

答案 2 :(得分:1)

正如你所说,你知道冒泡/隧道的概念,所以不要进入那个。但这就是这些事件的目的,即它们会让你知道控件上的鼠标按钮是否为Down或Up或它们的子节点。事件正常工作。对于你的场景,你应该使用按钮的Click事件它告诉鼠标按钮本身是否向下和向上。

由于