WPF中的隧道路由和冒泡路由事件

文章目录

  • 简介:
  • 一、事件最基本的用法
  • 二、理解路由事件


简介:

WPF中使用路由事件升级了传统应用开发中的事件,在WPF中使用路由事件能更好的处理事件相关的逻辑,我们从这篇开始整理事件的用法和什么是直接路由,什么是冒泡路由,以及什么是隧道路由。

一、事件最基本的用法

在基于事件驱动的开发中,把代码放在响应注册的事件的处理函数内,比如Click事件、MouseDown事件、MouseUp事件等等。每个控件响应自己的注册事件,有很多如果在事件上有相互关联和影响的事件,就要在一个业务逻辑里写比较多的代码。而路由事件主要的优势就是路由事件可以在元素树上进行传递,并且沿着元素树的传播途径被事件处理程序处理。这样我们写代码的过程中时就可以更好的组织代码到合适的位置。

WPF事件模型和WPF属性模型非常类似,与依赖项属性一样,路由事件由只读的静态字段表示,在静态构造函数中注册,并通过标准的.NET事件定义进行封装。这里我们只讲如何更好的使用。原理部分请看源码。比如ButtonBase提供的Click事件。

<Button Content="事件处理程序" Click="Button_Click"/>
private void Button_Click(object sender, RoutedEventArgs e)
{//这是Click事件处理程序代码部分。
}

在注册事件后,在事件处理程序中第一个参数 sender提供引发该事件的对象,第二个参数是EventArgs对象。在WPF中如果事件不需要传递额外的信息,可以使用RoutedEventArgs类,如果需要传递额外的信息,就要是有继承自RoutedEventArgs的对象。比如处理inkcanvas墨迹绘制的。比如处理多点触控的。这些都是变相继承RoutedEventArgs类。里面会包含在这种场景下更加多的信息。
在这里插入图片描述

注册事件的几种写法:

1)在XAML代码中<Button x:Name="EventMessageButton" Content="事件处理程序" MouseUp="EventMessageButton_MouseUp"/>
2)在cs代码中 EventMessageButton.MouseUp += EventMessageButton_MouseUp;
3)在cs代码中 EventMessageButton.MouseUp += new MouseButtonEventHandler(EventMessageButton_MouseUp);private void EventMessageButton_MouseUp(object sender, MouseButtonEventArgs e)
{//我是处理程序。
}

第一种写法: 我们使用XAML文件中在Button元素内使用MouseUp来创建后台事件处理代码 Btn_eventMessge_MouseUp

第二种写法: 我们在后台代码中使用MouseUp+=的方式注册。一种是New MouseButtonEventHandler传入方法名。一种是匿名的直接传入方法名,这三种注册方式达成的效果是一样的。

而这三种实际上使用的是事件封装器。另一种方式是通过使用UIElement.AddHandler来直接连接事件。这里看个人习惯把。但是各种写法主要解决的问题还是解耦,因为这些会关联到后面的命令,动画。模板。触发器。MVVM下的使用,等等。这是个比较长久的问题。所以在这里,能够使用,看得明白,目前这个阶段就可以了。

我们继续往下。解除关联

在注册事件的时候,最好先使用-=来解除关联,避免多次触发不合符预期的监听事件。断开使用-=或者使用UIElement.RemoveHandler来解除关联。 因为事件在多次+=注册事件处理程序是可行的。而事件的多词解除关系不会引发任何问题,因此不要担心+=和-=不匹配的问题。

public MainWindow(){InitializeComponent();EventMessageButton.MouseUp -= EventMessageButton_MouseUp;               EventMessageButton.MouseUp += EventMessageButton_MouseUp;}

二、理解路由事件

我们知道了事件可以在元素上注册事件处理程序,那么我们知道内容控件是可以相互嵌套各种奇奇怪怪的组合以达到自己想要的效果,在这种情况下我们假设一个比较常见的场景。我们有一个标签,标签中包含一个StackPanel面板,面板中包含一幅图片和2个文本。
在这里插入图片描述

<Label BorderBrush="Black" BorderThickness="1"><StackPanel><TextBlock Margin="3">我是图片标题</TextBlock><Image Source="1.png" Stretch="None"/><TextBlock Margin="3">我是图片正文</TextBlock></StackPanel>
</Label>

我们的控件来回嵌套内容结构很复杂了。但是我们想在用户点击时只在一个地方响应我们的代码。如果为每个元素都关联同一个事件处理程序,代码会很乱。而且难以维护。而路由事件就是为了解决这个问题的。路由事件分为三种:

1)和普通的.NET事件类似,直接路由事件(direct event) 他们源于一个元素,不传递给其他元素,比如MouseEnter事件,是直接路由事件。

2)向上传递的冒泡路由事件(bubbling event)比如MouseDown事件,是冒泡路由事件,该事件先由被单击的元素引发,接下来被该元素的父元素引发,然后被父元素的父元素引发,以此类推。直到元素树的顶部。

3)向下传递的隧道路由事件(tunneling event) 比如PreviewKeyDown事件,隧道路由事件在事件到达恰当的空间之前为预览事件和终止事件提供了机会,比如PreviewKeyDown事件可以截获是否按下了某个键,首先在窗口级别上,然后是更具体的容器,直到当按下时具有焦点的元素。

当使用EventManager.RegisterEvent()发给发注册路由事件时,需要传递一个RoutingStrategy枚举,指示希望用于事件的事件行为。

MouseUP和MouseDown事件都是冒泡路由事件,因此当在上面的图片中按下鼠标左键后顺序触发MouseDown事件的顺序是冒泡的。我们使用Snoop软件抓取一下过程:
在这里插入图片描述

从图中我们看到首先触发的是PreviewMouseDown的隧道路由。他可以让我们有机会预览事件或终止事件。我们看到了从MainWindow开始到最终的Image结束。我们没有终止路由。所以进行了下一轮的冒泡路由。从Image开始到MainWindow。

整个流程就结束了。我们看到路由事件提供了对事件处理非常丰富的功能。具体的隧道或冒泡行为可以参考RoutedEventArgs中的内容。

Source 属性是引发事件的的对象。 OriginalSource是最初是什么对象引发了事件。RoutedEvent为触发的事件提供的RoutedEvent对象。里面是需要用到的当前的参数,比如鼠标坐标,touch等等。Handled属性的作用是终止事件是否继续传递。

我们现在开始在这个例子上添加代码。用于演示我们怎么处理冒泡路由。

<Window x:Class="WPFEvent.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:WPFEvent"mc:Ignorable="d" MouseUp="EventResponseProcess_MouseUp"Title="MainWindow" Height="450" Width="800"><Grid Margin="3" MouseUp="EventResponseProcess_MouseUp"><Grid.RowDefinitions><RowDefinition Height="Auto"></RowDefinition><RowDefinition Height="*"></RowDefinition><RowDefinition Height="Auto"></RowDefinition><RowDefinition Height="Auto"></RowDefinition></Grid.RowDefinitions><Label Margin="5" Grid.Row="0" HorizontalAlignment="Left" Background="AliceBlue" BorderBrush="Black" BorderThickness="1" MouseUp="EventResponseProcess_MouseUp"><StackPanel MouseUp="EventResponseProcess_MouseUp"><TextBlock Margin="3" MouseUp="SomethingClicked">我是图片标题</TextBlock><Image Source="1.png" Stretch="None" MouseUp="EventResponseProcess_MouseUp"/><TextBlock Margin="3">我是图片正文</TextBlock></StackPanel></Label><ListBox Grid.Row="1" Margin="5" Name="MessageListBox"></ListBox><CheckBox Grid.Row="2" Margin="5" Name="HandlerCheckBox">Handle first event</CheckBox><Button Grid.Row="3" Margin="5" Padding="3" HorizontalAlignment="Right" Name="ClearButton" Click="ClearButton_Click">Clear List</Button></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 WPFEvent
{/// <summary>/// MainWindow.xaml 的交互逻辑/// </summary>public partial class MainWindow : Window{public MainWindow(){InitializeComponent();}protected int eventCounter = 0;private void EventResponseProcess_MouseUp(object sender, MouseButtonEventArgs e){eventCounter++;string message = $"#{ eventCounter}:\r\n Sender: {sender} \r\n Source: {e.Source} \r\n Original Source: {e.OriginalSource}"; MessageListBox.Items.Add(message);e.Handled = (bool)HandleCheckBox.IsChecked;}private void ClearButton_Click(object sender, RoutedEventArgs e)      { }}
}

和上图一样,我们尝试观察执行过程。看下触发过程,我们就能了解这个冒泡路由的工作过程了。上面写的这个例子。主要是让我们熟悉对于事件传入参数OriginalSource的使用。勾选界面上的HandleCheckBox复选框可以终止冒泡事件,从而只触发第一个Image的事件。可以自己写代码尝试一下整个过程。

有个方法可以接收终止的事件消息,使用AddHandler()重载的方法。
在这里插入图片描述

这里还有一个常用的技巧,事件的附加。

如下面的代码,在StackPanel中不存在Button的Click事件,但是可以通过ButtonBase.Click获取按钮的点击事件,此事件将会在StackPanel容器里面的任意按钮被点击时触发。

<StackPanel ButtonBase.Click="StackPanel_Click" Margin="5"><Button Content="按钮A" Click="Button_Click"/><Button Content="按钮B" Click="Button_Click"/><Button Content="按钮C" Click="Button_Click"/>
</StackPanel>

隧道路由这里就不写了,前面已经讲过。隧道路由命名都是Preview开头的。隧道路由全部结束了之后,同级的冒泡路由才开始。隧道路由主要是做预先处理,可以停止路由事件,也可以在事件处理程序中写一些对应的处理代码。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/27566.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

HTML基础标签解析:H1-H6、DIV与P的正确使用方法

在网页设计与开发中&#xff0c;HTML&#xff08;HyperText Markup Language&#xff0c;超文本标记语言&#xff09;是最为基础也是最为重要的组成部分之一。它定义了网页的内容结构和意义&#xff0c;使得浏览器能够正确地解析并展示网页给用户。本文将重点介绍HTML中的标题标…

WDF驱动开发-同步技术

使用自动同步 基于框架的驱动程序中几乎所有的代码都驻留在事件回调函数中。 框架会自动同步驱动程序的大部分回调函数&#xff0c;如下所示&#xff1a; 框架始终将 常规设备对象、 功能设备对象 (FDO) 和 物理设备对象 (PDO) 事件回调函数同步&#xff0c;以便每个设备一次…

vscode python环境配置

在Visual Studio Code&#xff08;VSCode&#xff09;中配置Python环境是一个相对直接的过程。以下是配置VSCode Python环境的详细步骤&#xff1a; 1. 安装Python 下载Python安装包&#xff1a;访问Python官方网站&#xff08;https://www.python.org/downloads/&#xff09…

Java高阶数据结构-----并查集(详解)

目录 &#x1f9d0;一.并查集的基本概念&实例&#xff1a; &#x1f92a;二.并查集代码&#xff1a; &#x1f602;三&#xff1a;并查集的一些习题&#xff1a; A.省份数量 B.等式方程的可满足性 &#x1f9d0;一.并查集的基本概念&实例&#xff1a; 并查集概念&…

向量化在人工智能领域的深度实践:技术革新与效率提升

在人工智能&#xff08;AI&#xff09;的飞速发展中&#xff0c;向量化技术作为一种基础且关键的数据处理手段&#xff0c;正日益受到广泛关注。向量化是将文本、图像、声音等数据转换为数值向量的过程&#xff0c;这些向量能够表示原始数据的特征和语义信息&#xff0c;为深度…

13.ChatGPT 大模型训练核心技术

ChatGPT 大模型训练核心技术 从 GPT-3 到 ChatGPT 的大模型训练技术演进 基于RLHF训练大模型的三阶段 • Domain Specific Pre-Training: Fine-tune a pre-trained LLM on raw text with a Causal Language Modelling Objective.• Supervised fine-tuning: Fine-tune the do…

外网访问公司内网服务器?

【天联】组网天联可以解决不同地区电脑与电脑、设备与设备、电脑与设备之间的信息远程通信问题。在全国各主要节点部署加速服务器&#xff0c;实现在低带宽、跨运营商的网络环境下高速访问&#xff1b;这为公司内网服务器提供了一个可行的外网访问解决方案。 在现代办公环境中…

图书管理系统的要点和难点以及具体应用场景

图书管理系统是一个集成了管理科学、系统科学、运筹学、统计学和计算机科学等学科知识的综合性系统。该系统主要用于图书馆或书店等机构的图书资源管理,通过收集、传递、加工、保存、维护和使用图书信息,帮助图书馆实现其规划目标,提高管理效率。以下是关于图书管理系统的详…

CANoe连接Option Scope使用方法

系列文章目录 文章目录 系列文章目录前言一、前提条件二、CANoe配置三、PicoScope接线四、CANoe捕捉报文五、眼图功能前言 本文档主要介绍如何使用CANoe Option .Scope捕获CAN总线上的物理波形,并利用眼图进行分析。 一、前提条件 使用CANoe Option .Scope,需要具备以下条件…

AI绘画入门教程(非常详细)从零基础入门到精通Midjourney提示词,咒语

Microorganisms infiltrating through brain-machine interfaces --v 6.0 Microorganisms infiltrating through brain-machine interfaces ,redpupil --v 6.0 Microorganisms infiltrating through brain-machine interfaces,billion girls dream --v 6.0 --niji 6 “动漫风”…

Qt信号槽的回调机制

问&#xff1a;Qt强大的地方在哪里&#xff1f; 答&#xff1a;跨平台、信号槽。。。 问&#xff1a;信号槽是什么&#xff1f; 答&#xff1a;回调函数 问&#xff1a;怎么个回调法子 答&#xff1a;。。。 成果 信号槽本身实现过程是有些复杂的&#xff0c;所以本人参考…

50【Aseprite 作图】模糊工具 笔刷

1 模糊工具 2 笔刷 然后 选中 后 Ctrl B&#xff0c;就变成笔刷了 可以按住shift &#xff0c;像画一条线一样 或者用矩形、圆形工具、油漆桶工具 在上方可以选择笔刷的不同形式&#xff0c;如果是“图案与来源对齐”&#xff0c;就是来源不变&#xff0c;笔刷不会覆盖之前…

网安要求关闭所有系统标签页后,自动去除登录人信息(包括直接关闭整个浏览器)

暂时没找到什么优美得解决办法&#xff0c;如遇到&#xff0c;请留言&#xff0c;谢谢浏览器没有关闭事件&#xff0c;只有在关闭时会调用beforeunload&#xff0c;unload&#xff0c;但是再刷新时会调用beforeunload&#xff0c;unload&#xff0c;onload 因此关闭再打开与刷新…

每日5题Day24 - LeetCode 116 - 120

每一步向前都是向自己的梦想更近一步&#xff0c;坚持不懈&#xff0c;勇往直前&#xff01; 第一题&#xff1a;116. 填充每个节点的下一个右侧节点指针 - 力扣&#xff08;LeetCode&#xff09; /* // Definition for a Node. class Node {public int val;public Node left;…

LeetCode | 171.Excel表列序号

这道题涉及到字符串和进制转换&#xff0c;首先我们先创建一个A-Z到1-26的map映射&#xff0c;方便我们后续遍历字符串转换&#xff0c;然后对字符串从后往前遍历&#xff0c;依次加上对应权重&#xff0c;注意越往前的权重越大&#xff0c;要记得对应乘上26的对应方数 class …

[Day 10] 區塊鏈與人工智能的聯動應用:理論、技術與實踐

AI在各行業的應用實例 人工智能&#xff08;AI&#xff09;作為當今最具影響力的技術之一&#xff0c;已經在各行業中展現出廣泛的應用前景。從金融到醫療、零售到製造&#xff0c;AI正在改變各行業的運營模式、提升效率、降低成本並創造新的機會。本文將深入探討AI在幾個主要…

Nginx 搭建 lnmp

一.编译安装Nginx 1.新建用户前期准备 官网下载nginx安装包 https://nginx.org/en/download.html yum -y install gcc pcre-devel openssl-devel zlib-devel openssl openssl-devel #安装依赖包 useradd -M -s /sbin/nologin nginx #新建nginx用户便于管理 2.切换到/opt…

自动控制理论---线性时不变系统的单位脉冲响应

1、实验设备 PC计算机1台&#xff0c;MATLAB软件1套。 2.实验目的&#xff1a; 学习并理解线性时不变系统的单位脉冲响应的计算方法。掌握MATLAB编程&#xff0c;计算整个系统的单位脉冲响应。 3.实验原理说明&#xff1a; 单位脉冲响应是指在输入信号为单位脉冲序列时&am…

酷开科技丨酷开系统大屏游戏新体验,夏日宅家娱乐新方案

随着夏日的临近&#xff0c;人们开始寻找各种方式来打发炎热天气中的空闲时间。不论是与朋友们聚会、追剧&#xff0c;还是与队友们一起沉浸在游戏中&#xff0c;酷开科技都能为你提供好的解决方案。如果你也渴望在家中享受激情四溢的游戏对战&#xff0c;那么酷开系统将是你的…

[Java基本语法] 继承与多态

&#x1f338;个人主页:https://blog.csdn.net/2301_80050796?spm1000.2115.3001.5343 &#x1f3f5;️热门专栏:&#x1f355; Collection与数据结构 (92平均质量分)https://blog.csdn.net/2301_80050796/category_12621348.html?spm1001.2014.3001.5482 &#x1f9c0;线程与…