我理解冒泡和隧道是如何工作的。但是,我对使用它们很困惑。 原因如下:
我想处理鼠标点击事件。要冒泡它,有MouseDown
,并且为了隧道它,有PreviewMouseDown
。但是,MouseDown
并不一定意味着用户点击了控件。可能是用户按下按钮并离开它以取消点击。
如果没有点击按钮,我不想改变任何东西。
所以我的问题是,Bubbling / Tunneling策略有用吗?
答案 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
许多标准控件都会监听事件,例如KeyDown
,MouseDown
等。例如 - DataGrid
控件。我想按下回车键,该功能被称为添加记录。但是DataGrid
已经有KeyDown
个事件,因此不会引发该事件。因此,您必须在隧道事件中执行您的逻辑 - PreviewKeyDown
,它将在KeyDown
事件之前运行。这同样适用于RichTextBoxControl
。
Bubbling
有时,您需要一个特定事件的全局处理程序,因此它适用于VisualTree中的所有控件。当然,直接的事件你不能这样做。因此在舞台上出现Bubbling事件。
另一个原因是WPF的意识形态。此Button
可以包含任何内容:Image
,另一个Button
等:
用户可以点击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
:
答案 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
事件它告诉鼠标按钮本身是否向下和向上。
由于