第5章 路由事件(1)——概述

一、概述 

属性和事件是.NET抽象模型的核心部分,是每位.NET编程人员都十分熟悉的主题,但是WPF将属性和事件都进行了升级。WPF创建了一个新的依赖属性系统,重写了传统的.NET属性以提高性能并集成新功能(例如数据绑定和动画)。同时使用更高级的路由事件功能替换普通的.NET事件,使事件可在元素树中向上冒泡和向下隧道传播,并沿着传播路径被事件处理程序处理。

二、路由事件有三种形式

1、直接路由事件

直接路由事件与普通.NET事件类似,他们源于一个元素,不传递给其他元素。例如,MouseEnter事件(当鼠标指针移到元素上时发生)是直接路由事件。

2、冒泡路由事件

在包含层次中向上传递。该事件首先由被单击的元素引发,接下来被该元素的父元素引发,然后被父元素的父元素引发,依次类推,直到WPF到达元素树的顶部为止。例如,MouseDown事件就是冒泡路由事件。

3、隧道路由事件

在包含层次中向下传递。隧道路由事件在事件到达恰当的控件之前为预览事件(甚至终止事件)提供了机会。例如,通过PreviewKeyDown事件可截获是否按下某个键。首先在窗口级别上,然后是更具体的容器,直到到达当按下键时具有焦点的元素。

三、路由事件的便利性

WPF中的许多控件都是内容控件,而内容控件可包含任何类型以及大量的嵌套内容。例如,有一个文本标签,其中包含一个StackPanel面板,该面板又包含两个文本和一个图像,具体XAML代码如下:

<Window x:Class="WpfApplication5_1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApplication5_1"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <StackPanel>
        <Label BorderBrush="Black" BorderThickness="1">
            <StackPanel>
                <TextBlock Margin="3">Image and picture label</TextBlock>
                <Image Source="happyface.jpg" Stretch="None"></Image>
                <TextBlock Margin="3">Courtesy of the StackPanel</TextBlock>
            </StackPanel>
        </Label>
    </StackPanel>
</Window>
效果图如下:


放在WPF窗口中的所有元素都在一定层次上继承自UIElement类,包括Label、StackPanel、TextBlock和Image等。UIElement定义了一些核心事件。例如,每个继承自UIElement的类都提供MouseDown事件和MouseUp事件。

元素和控件基类框图如下:


如果现在有这样一个需求,要求单击Lable标签来触发同一个事件处理程序,显然可以为Lable标签内的每个元素的MouseDown或MouseUp事件关联同一个事件处理程序,但这样会使标记变得杂乱无章且难以维护。

注意:此处为什么使用MouseDown或MouseUp事件而不使用Click事件,这是因为大多数WPF元素没有提供Click事件,而是提供了更直接的MouseDown或MouseUp事件。Click事件专用于继承自ButtonBase的控件。

MouseDown或MouseUp事件都是冒泡路由事件,此时可在标签级别或更高级别处理MouseDown或MouseUp事件,就可以实现无论单击标签内的哪个元素都可以触发同一个事件处理程序,而代码仅需要一行。具体代码如下:

XAML标记代码:

<Window x:Class="WpfApplication5_1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApplication5_1"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <StackPanel>
        <Label BorderBrush="Black" BorderThickness="1" MouseDown="lbl_Event">
            <StackPanel>
                <TextBlock Margin="3">Image and picture label</TextBlock>
                <Image Source="happyface.jpg" Stretch="None"></Image>
                <TextBlock Margin="3">Courtesy of the StackPanel</TextBlock>
            </StackPanel>
        </Label>
    </StackPanel>
</Window>

VS后台代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace WpfApplication5_1
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void lbl_Event(object sender, MouseButtonEventArgs e)
        {
            MessageBox.Show("触发源:" + e.Source); //e.Source指示引发了事件的对象
        }
    }
}

四、路由事件的两个参数

所有WPF事件都为事件签名使用熟悉的.NET约定。每个事件处理程序都有两个参数,具体如下:

1、第一个参数:sender指事件触发时调用该事件的对象。例如,上例中指的是Label对象。

2、第二个参数:RoutedEventArgs或其派生类。

RoutedEventArgs类属性
名称说明
Source指示引发了事件的对象。例如,上例中点击的Image或TextBlock对象。
OriginalSource指示最初是什么引发了事件。OriginalSource属性值通常与Source属性值相同
RoutedEvent为事件处理程序提供RoutedEvent对象
如果用同一个事件处理程序处理不同的事件,这一信息非常有用
Handled该属性允许终止事件的冒泡或隧道过程。
如果控件将Handled属性设为true,那么事件就不会继续传递,也不会再为其他任何元素引发该事件
在WPF中,如果事件不需要传递任何额外细节,可使用RoutedEventArgs类,该类包含了有关如何传递事件的一些细节。如果事件确实需要传递额外的信息,那么需要使用更特殊的继承自RoutedEventArgs的对象。因为每个WPF事件参数类都继承自RoutedEventArgs类,所以每个WPF事件处理程序都可访问与事件路由有关的信息。

五、代码下载

WpfApplication5_1.rar提取码:xu8v

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值