【问题标题】:When are tunneling and bubbling events useful in WPF?WPF 中的隧道和冒泡事件何时有用?
【发布时间】:2013-09-07 09:59:45
【问题描述】:

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

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

所以我的问题是,冒泡/隧道策略有什么用?

【问题讨论】:

    标签: c# wpf mouseevent event-bubbling mousedown


    【解决方案1】:

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

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

    这里指定了RoutedEventArgs,所以是路由事件。因为 preview 没有在名字中指定,所以这个 Bubble 事件。这可以通过以下方式证明:

    <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 中的所有控件。自然,一个直接的事件你是做不到的。因此在舞台上出现了冒泡事件。

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

    用户可以点击Button中的TextBlock/Image。我们如何知道点击是在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的结果:

    【讨论】:

    • 但是,据我所知,点击是直接事件而不是冒泡事件。
    • @SanSolo:如果是直接的,那么消息Button Test clicked! 没有出现。我们为Grid 设置了一个处理程序,而不是Button,然后单击Button,该事件对Grid 起作用。 Button 的事件向上移动,来到Grid。直接点击事件,据我所知,一直在WinForms.
    • 是的,你是对的。我运行了您提供的示例来检查发件人、来源和原始来源。 Thw 值分别为 Grid、Button 和 Button:Test。那么默认情况下,所有 WPF 事件都是冒泡事件吗?这令人困惑...隧道事件有 preview 关键字,但不知道哪些是冒泡事件。
    • @SanSolo:默认情况下,所有事件都是RoutedEvents。没错,如果名称在 preview 中,则它是隧道事件。您可以查看我在回答中给您的文章。
    • 谢谢。我在another msdn article 上发现了这一点:>根据事件定义,事件路由可以沿两个方向之一行进,但通常路由从源元素行进,然后通过元素树向上“冒泡”,直到到达元素树根(通常是页面或窗口)。所以,默认策略是冒泡。
    【解决方案2】:

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

    假设你给一个按钮一个由单个矩形组成的非常简单的外观,并提供一段简单的文本作为内容即使有这样基本的视觉效果,仍然存在两个元素:文本和矩形。按钮应该无论鼠标是在文本还是矩形上,都响应鼠标单击。在标准 .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 遍历 用户界面元素树,调用附加到的路由事件的所有处理程序 从原始元素一直到用户界面树根的任何节点。

    【讨论】:

    • 该答案阐明了对冒泡/隧道的需求,这是我的问题的标题。但是,我仍然对我们为什么要使用 MouseUp 或 MouseDown 感到困惑,因为它不是像 Click 这样的决定性操作。 MousewheelUp/Down 我可以看到它有用的场景。但是在 MouseUp 的情况下,我们改变了一些东西,用户离开按钮,没有点击......我们会在哪里使用它?
    【解决方案3】:

    正如你所说,你知道冒泡/隧道的概念,所以不要讨论这个。但这就是这些事件的目的,即它们让您知道控件或其子项上的鼠标按钮是向下还是向上。事件工作正常。对于您的场景,您应该使用按钮的 Click 事件告诉如果鼠标在按钮本身上上下移动。

    谢谢

    【讨论】:

    • 点击将是一个直接事件。我的困惑是关于冒泡/隧道事件的使用
    猜你喜欢
    • 1970-01-01
    • 2013-05-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多