美文网首页简书面面观
WPF之路-路由事件

WPF之路-路由事件

作者: 东南有大树 | 来源:发表于2018-09-14 14:08 被阅读44次

理解路由事件

路由事件是一种可以针对元素树中的多个侦听器而不是仅仅针对引发该事件的对象调用处理程序的事件,也就是说,触发事件源的父级或子级如果都有对该事件的监听,则都能触发事件

路由事件与一般事件的区别在于:路由事件是一种用于元素树的事件,当路由事件触发后,它可以向上或向下遍历可视树和逻辑树,他用一种简单而持久的方式在每个元素上触发,而不需要任何定制的代码(如果用传统的方式实现一个操作,执行整个事件的调用则需要执行代码将事件串联起来)

路由事件的路由策略

所谓的路由策略就是指:路由事件实现遍历元素的方式

路由事件一般使用以下三种路由策略:

  1. 冒泡:由事件源向上传递一直到根元素
  2. 直接:只有事件源才有机会响应事件
  3. 隧道:从元素树的根部调用事件处理程序并依次向下深入直到事件源

一般情况下,WPF提供的输入事件都是以隧道/冒泡对实现的。隧道事件常常被称为Preview事件

冒泡

程序设计思路是,将多个Grid嵌套起来,构成父子结构,在最底层支Grid上定义一个按钮,绑定一个单击事件,并且按钮的所有低级元素都绑定该事件,它们使用同一个事件处理程序;再定义一个ListBox,当事件处理程序执行的时候,打印出事件激发者的名字,这样便能看到事件执行的顺序

下图是界面设计:

下面是XMAL代码,按钮和每一个Grid都绑定了Button.Click="Btn_Click"

<Window x:Class="WPF_CODE.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-->
    <Grid Button.Click="Btn_Click" Name="Grid_1" Background="#FF43AEAE">
        <!--定义两行-->
        <Grid.RowDefinitions>
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>
        </Grid.RowDefinitions>
        
        <!--第二层Grid-->
        <Grid Button.Click="Btn_Click" Name="Grid_2"  Margin="10" Background="#FF8D888D" Grid.Row="0">
            <!--定义两列-->
            <Grid.ColumnDefinitions>
                <ColumnDefinition></ColumnDefinition>
                <ColumnDefinition></ColumnDefinition>
            </Grid.ColumnDefinitions>
            
            <!--第三层左侧Grid-->
            <Grid Button.Click="Btn_Click" Name="Grid_3_Left" Grid.Column="0" Background="#FF3D8F3A" Margin="10">
                <!--添加一个按钮-->
                <Button Button.Click="Btn_Click" Name="ButtonLeft" Width="80" Height="50" Content="Hello"/>
            </Grid>
            
            <!--第三层右侧Grid-->
            <Grid Button.Click="Btn_Click" Name="Grid_3_Right" Grid.Column="1" Background="#FFC95E3E" Margin="10">
                <!--添加一个按钮-->
                <Button Button.Click="Btn_Click" Name="ButtonRight" Width="80" Height="50" Margin="10" Content="World"></Button>
            </Grid>
            
        </Grid>
        
        <!--定义一个ListBox,用于输出结果-->
        <ListBox Name="Print_List"  Grid.Row="1"/>
        
    </Grid>
    
</Window>

下面是后端代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
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 WPF_CODE
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        // 事件处理程序
        private void Btn_Click(object sender, RoutedEventArgs e)
        {
            //sender是指由谁激发了这个事件处理程序,它可以获取到触发对象
            //通过(sender as FrameworkElement).Name转换,将触发控件的名称拿出来,
            string message = "触发者:"+(sender as FrameworkElement).Name.ToString();
            this.Print_List.Items.Add(message);

            //e包含了与事件相关的一些参数,e.Handled如果设置为True,则表示冒泡不再继续
            //e.Handled = true;
        }
    }
}

运行程序,点击左侧按钮,结果如下:

点击右侧按钮,结果如下:

可以看出,事件首先在源元素上触发,然后从每一个元素向上沿着树传递,直到到达根元素为止(或者直到处理程序把事件标记为已处理为止),从而调用这些元素中的路由事件

如果将事件处理程序里的e.Handled = true;代码放开,效果如下

//e包含了与事件相关的一些参数,e.Handled如果设置为True,则表示冒泡不再继续
e.Handled = true;

即事件处理程序只要被触发一次,并不会发生冒泡

隧道

隧道的执行顺序与冒泡正好相反,直接看例子,然后再解释,将上便中所有的Click事件改为PreviewMouseDown事件,而绑定的事件处理程序不变

XAML代码如下:

<Window x:Class="WPF_CODE.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-->
    <Grid PreviewMouseDown="Btn_Click" Name="Grid_1" Background="#FF43AEAE">
        <!--定义两行-->
        <Grid.RowDefinitions>
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>
        </Grid.RowDefinitions>
        
        <!--第二层Grid-->
        <Grid PreviewMouseDown="Btn_Click" Name="Grid_2"  Margin="10" Background="#FF8D888D" Grid.Row="0">
            <!--定义两列-->
            <Grid.ColumnDefinitions>
                <ColumnDefinition></ColumnDefinition>
                <ColumnDefinition></ColumnDefinition>
            </Grid.ColumnDefinitions>
            
            <!--第三层左侧Grid-->
            <Grid PreviewMouseDown="Btn_Click" Name="Grid_3_Left" Grid.Column="0" Background="#FF3D8F3A" Margin="10">
                <!--添加一个按钮-->
                <Button PreviewMouseDown="Btn_Click" Name="ButtonLeft" Width="80" Height="50" Content="Hello"/>
            </Grid>
            
            <!--第三层右侧Grid-->
            <Grid PreviewMouseDown="Btn_Click" Name="Grid_3_Right" Grid.Column="1" Background="#FFC95E3E" Margin="10">
                <!--添加一个按钮-->
                <Button PreviewMouseDown="Btn_Click" Name="ButtonRight" Width="80" Height="50" Margin="10" Content="World"></Button>
            </Grid>
            
        </Grid>
        
        <!--定义一个ListBox,用于输出结果-->
        <ListBox Name="Print_List"  Grid.Row="1"/>
        
    </Grid>
    
</Window>

运行程序,查看效果:

可以看出,隧道是指事件首先是从根元素上被触发,然后从每一个元素向下沿着树传递,直到到达根元素为止(或者直到到达处理程序把事件标记为已处理为止),他的执行方式正好与冒泡策略相反

所有的隧道事件都以Preview开头

后台代码记得将e.Handled=true注释掉

直接策略

事件仅仅在源元素上触发,这个与普通的.Net事件的行为相同,不同的是这样的事件仍然会参与一些路由事件的特定机制,如事件触发器等;该事件唯一可能的处理程序是与其挂接的委托

相关文章

  • WPF之路-路由事件

    理解路由事件 路由事件是一种可以针对元素树中的多个侦听器而不是仅仅针对引发该事件的对象调用处理程序的事件,也就是说...

  • WPF 路由事件 与 命令

    事件 事件的前身是消息(在窗体点左键会生成一条携带参数的消息加入windows待处理消息队列,当windows处理...

  • WPF路由

    举例:窗口-用户控件-布局控件-…-按钮 按钮的点击事件:先由按钮的Click相应,然后….,然后布局控件,然后用...

  • WPF之路-键盘与鼠标事件

    键盘事件 事件类型分为以下几个类型 生命周期事件:在元素加载与卸载的时候发生 鼠标事件:鼠标动作 键盘事件:键盘动...

  • WPF简介

    目录 什么是WPF? WPF的历史? 为什么要用WPF及WPF作用 WPF与winForm区别? 什么是WPF? ...

  • 浅谈WPF的数据绑定,路由事件和MVVM模式

    注:本文出现的所有代码为了简单明了均省略了很多细节部分,只注重原理,直接复制粘贴运行得不到对应的结果。 WPF的数...

  • WPF例4-查找触发路由事件的按钮

    一、MainWindow中设置捕获ButtonBase.Click事件,触发Window_Click函数 Main...

  • WPF之路-控件类

    控件类是指与用户有交互作用的控件,例如文本框、按钮等 设置控件背景颜色 首先在界面定义一个按钮 从后端设置按钮的背...

  • WPF的通关之路

    首先说明两点,一是个人是业余爱好桌面开发(单纯以找工作去学客户端开发,这种行为不太推荐哦),二是WPF的样式比Wi...

  • 路由事件

    二、使用 2.1 例子 2.2 路由类型 冒泡路由(从下到上) 隧道路由(从上到下) 直接路由 2.3 添加处理程...

网友评论

    本文标题:WPF之路-路由事件

    本文链接:https://www.haomeiwen.com/subject/qzdogftx.html