-
- UIElement类为键盘、鼠标、指示笔输入定义了许多路由事件。大多数路由事件是冒泡事件,但许多事件与管道事件是配对的。为许多不同的行为提供一对事件是为了给元素一个有效地取消事件或者在事件即将发生前修改事件的机会。
- 管道事件按照惯例,它们的名字中都有一个Preview前缀,在它们的配对冒泡事件发生之前,这些管道事件会立即被触发。
- 冒泡事件使用实例
- 右击任何一个ListBoxItem时,Window元素不会收到MouseRightButtonDown事件,这是因为ListBoxItem内部已经处理了这个事件,与MouseLeftButtonDown事件(终止冒泡)一样,以便实现item(项)的选择。
- 如果右击一个Button元素,Window会收到MouseRightButtonDown事件,但是设置Button的边界属性不会有任何可视效果。这是Button的默认可视树造成的,Button的可视树没有Border元素。
- 处理鼠标中键的事件可以通过更加通用的MouseDown和MouseUp事件来处理。传入这样的事件处理程序的参数包括一个MouseButton枚举值,它表示鼠标状态刚刚改变,它们是Left、Right、Middle、XButton1或XButton2,还有一个对应的MouseButtonState枚举值,表示这个按钮是Pressed还是Released。
- 终止管道传递或者冒泡仅仅是一种假象而已。更加准确的说法应该是,当一个路由事件标记为已处理时,管道传递和冒泡仍然会继续,但默认情况下,事件处理程序只会处理没有处理过的事件。为了让事件处理程序处理那些已经处理过的事件,可以使用AddHandler的重载添加一个布尔型的参数handledEventsToo,来标识是否对已处理过的事件进行处理。
3.3.3 路由事件实践
例如:
PreviewKeyDown就是一个管道事件,在KeyDown冒泡事件之前被触发。在PreviewKeyDown中标记它为“已处理”,这样不仅可以停止管道事件PreviewKeyDown,还可以防止冒泡的KeyDown事件的触发。
XAML文档
<Window x:Class="WpfApplication1.AboutDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
MouseRightButtonDown="AboutDialog_MouseRightButtonDown"
Title="About WPF Unleashed"
SizeToContent="WidthAndHeight"
Background="OrangeRed">
<StackPanel>
<Label FontWeight="Bold"
FontSize="20"
Foreground="White">
WPF Unleashed (Version 3.0)
</Label>
<Label>
© 2006 SAMS Publishing
</Label>
<Label>
Installed Chapters:
</Label>
<ListBox>
<ListBoxItem>
Chapter 1
</ListBoxItem>
<ListBoxItem>
Chapter 2
</ListBoxItem>
</ListBox>
<StackPanel Orientation="Horizontal"
HorizontalAlignment="Center">
<Button MinWidth="75"
Margin="10">
Help
</Button>
<Button MinWidth="75"
Margin="10">
OK
</Button>
</StackPanel>
<StatusBar>
You have successfully registered this product.
</StatusBar>
</StackPanel>
</Window>
对应的代码隐藏文件
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
namespace WpfApplication1
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class AboutDialog : Window
{
public AboutDialog()
{
InitializeComponent();
}
private void AboutDialog_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
{
// 显示这个事件的信息
this.Title = "Source = " + e.Source.GetType().Name + ", OriginalSource = " + e.OriginalSource.GetType().Name + " @ " + e.Timestamp;
// 该示例中,所有可能从Control派生而来的源
Control source = e.Source as Control;
// 调整源控件的边框宽度
if (source.BorderThickness != new Thickness(5))
{
source.BorderThickness = new Thickness(5);
source.BorderBrush = Brushes.Black;
}
else
{
source.BorderThickness = new Thickness(0);
}
}
}
}
注意:
例如:
this.AddHandler(Window.MouseRightButtonDownEvent, new MouseButtonEventHandler(this.AboutDialog_MouseRightButtonDown), true/*handledEventsToo*/);
这样处理的结果就是无论MouseRightButtonDown事件是否处理完,都会执行AoubtDialog_MouseRightButtonDown的逻辑。