在WPF中,例如,可以构建一个包含图形的按钮,创建一个具有文本和图片混合内容的标签,或者为了实现滚动或折叠的显示效果在一个特定的容器中放置内容。甚至可以多此重复嵌套,直到达到您所希望的层次深度。
这种可以任意嵌套的能力也带来了一个有趣的问题。例如,假设有一个标签,它包含一个StackPanel面板,该面板又包含了两块文本图像:
<Label BorderBrush="Black" BorderThickness="1"> <StackPanel> <TextBlock Margin="3">Image and text label</TextBlock> <Image Source="c:1.jpg" Stretch="None" /> <TextBlock Margin="3">Courtesy of the StackPanel</TextBlock> </TextBlock> </StackPanel> </Label>
正如您已经知道的,放在WPF窗口中的所有要素都在一定层次上继承自UIElement类,包括Label、StackPanel、TextBlock 和 Image 。 UIElement 定义了一些核心事件。例如,每个继承自 UIElement 的类都具有一个 MouseDown 事件和 MouseUp 事件。
但是当单击上面这个特殊标签中的图像部分时,想一想会发生什么事情?很明显,印发Image.MouseDown 事件和 Image.MouseUp 事件是合情合理的。但是我们一般实际期望的结果并不是这样,而是无论用户单击了图像、某块文本还是标签内的空白处。不管在什么位置点击都触发同一个事件来进行处理。
因为MouseUp事件和MouseDown事件都是冒泡路由事件,所以他们会依次向上传递事件触发,如:点击TextBlock 会依次触发:TextBlock、StackPanel、Lable、.....直到window窗体为最后一站传递点。也许这也并不是我们希望的结果,幸运的是在 WPF 中所有事件的参数类都继承自 RoutedEventArgs ,任何事件处理程序都可以使用这些属性。其中有一个 Handled 属性,则是可以终止继续往上层次冒泡的属性。该属性为True时,则终止冒泡。
下面以一个例子来实验这种冒泡路由事件效果:
效果:
XAML代码:
<Window x:Class="_1015_BubbledEvent.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="350" Width="525"> <Grid Margin="3"> <Grid.RowDefinitions> <RowDefinition Height="auto"/> <RowDefinition Height="*"/> <RowDefinition Height="auto"/> <RowDefinition Height="auto"/> </Grid.RowDefinitions> <Label Margin="5" Grid.Row="0" HorizontalAlignment="Left" Background="AliceBlue" BorderBrush="Black" BorderThickness="1" MouseUp="SomethingClicked"> <StackPanel MouseUp="SomethingClicked"> <TextBlock Margin="3" MouseUp="SomethingClicked">Image and text label</TextBlock> <Image Source="c:1.jpg" Stretch="Fill" Width="100" Height="100" MouseUp="SomethingClicked"/> <TextBlock Margin="3" MouseUp="SomethingClicked">Courtesy of the StackPanel</TextBlock> </StackPanel> </Label> <ListBox Grid.Row="1" Margin="5" Name="lstMessage"/> <CheckBox Grid.Row="2" Margin="5" Name="chkHandle">Handle first event</CheckBox> <Button Grid.Row="3" Margin="5" Padding="3" HorizontalAlignment="Right" Name="cmdClear" Click="cmdClear_Click_1">Clear List</Button> </Grid> </Window>
注意:代码中包含了在C:1jpg 文件,请自行随意找一个文件代替吧。
C#代码:
int _eventCounter = 0; private void SomethingClicked(object sender, MouseButtonEventArgs e) { _eventCounter++; string message = "#" + _eventCounter.ToString() + ": " + " Sender: " + sender.ToString() + " " + " Source: " + e.Source + " " + " Original Source: " + e.OriginalSource; lstMessage.Items.Add(message); e.Handled = (bool)chkHandle.IsChecked; } private void cmdClear_Click_1(object sender, RoutedEventArgs e) { _eventCounter = 0; lstMessage.Items.Clear(); }
源码下载:http://files.cnblogs.com/andrew-blog/1015_BubbledEvent.rar
使用工具:VS2012