首页 > 其他分享 >WPF事件(事件&路由事件)

WPF事件(事件&路由事件)

时间:2023-05-29 21:23:41浏览次数:45  
标签:控件 Tree 事件 WPF 路由 响应者

本篇文章学习于: 刘铁猛老师《深入浅出WPF》

WPF 的树型结构

路由(Route)一词的大意是这样:起点与终点间有若干个中转站,从起点出发后经过每个甲转站时要做出选择,最终以正确(比如最短或者最快)的路径到达终点。
WPF把这种直接消息模型升级为可传递的消息模型——前面我们已经知道WPF 的UI是由布局组件和控件构成的树形结构,当这棵树上的某个结点激发出某个事件时,程序员可以选择以传统的直接事件模式让响应者来响应之,也可以让这个事件在UI组件树沿着一定的方向传递且路过多个中转结点,并在这个路由过程中被恰当地处理。
你可以把WPF的路由事件看成是一只小蚂蚁,它可以从树的基部向顶部(或反向)目标爬行,每路过一个树枝的分叉点就会把消息带给这个分叉点。
WPF中有两种“树”:一种叫逻辑树(Logical Tree);一种叫可视元素树(Visual Tree )。
下图就是Logical Tree,它的每个结点不是布局组件就是控件。
那什么是Visual Tree 呢?我们知道,如果把一片树叶放在放大镜下观察,你会发现这片叶子也像一棵“树”一样——有自己的基部并向上生长出多级分叉。在WPF的 Logical Tree 上,充当叶子的一般都是控件,如果我们把WPF的控件也放在“放大镜”下去观察,你会发现每个WPF 控件本身也是一棵由更细微级别的组件(它们不是控件,而是一些可视化组件,派生自Visual类)组成的树。
image.png
如果想在Logical Tree 上导航或查找元素,可以借助LogicalTreeHelper类的static方法来实现:

  • BringIntoView:把选定元素带进用户可视区域,经常用于可滚动的视图。
  • FindLogicalNode:按给定名称(Name属性值)查找元素,包括子级树上的元素。GetChildren:获取所有直接子级元素。
  • GetParent:获取直接父级元素。

现在我们已经知道,WPF 的UI可以表示为Logical Tree和Visual Tree,那么当一个路由事件被激发后是沿着Logical Tree传递还是沿着Visual Tree传递呢?答案是Visual Tree,只有这样,“藏”在Template里的控件才能把消息送出来。

事件详解

事件的前身是消息,事件模型隐藏了消息机制的很多细节,让程序的开发变得简单。
烦琐的消息驱动机制在事件模型中被简化为3个关键点:

  • 事件的拥有者:即消息的发送者。事件的宿主可以在某些条件下激发它拥有的事件,即事件被触发。事件被触发则消息被发送。
  • 事件的响应者:即消息的接收者、处理者。事件接收者使用其事件处理器(Event Handler)对事件做出响应。
  • 事件的订阅关系:事件的拥有者可以随时激发事件,但事件发生后会不会得到响应要看有没有事件的响应者,或者说要看这个事件是否被关注。如果对象A关注对象B的某个事件是否发生,则称A订阅了B的事件。更进一步讲,事件实际上是一个使用event关键字修饰的委托(Delegate)类型成员变量,事件处理器则是一个函数,说A订阅了 B的事件,本质上就是让B.Event 与 A.EventHandler关联起来。所谓事件激发就是B.Event被调用,这时,与其关联的A.EventHandler就会被调用。

示例:
image.png
这就是直接事件模型,这样至少有两个弊端:
(1)每对消息是“发送→响应”关系,必须建立显式的点对点订阅关系。
(2)事件的宿主必须能够直接访问事件的响应者,不然无法建立订阅关系。
路由事件的出现很好地解决了上述两种情况中出现的问题。

路由事件

为了降低由事件订阅带来的耦合度和代码量,WPF推出了路由事件机制。
路由事件与直接事件的区别在于:

  • 直接事件激发时,发送者直接将消息通过事件订阅交送给事件响应者,事件响应者使用其事件处理器方法对事件的发生做出响应、驱动程序逻辑按客户需求运行;
  • 路由事件的事件拥有者和事件响应者之间则没有直接显式的订阅关系,事件的拥有者只负责激发事件,事件将由谁响应它并不知道,事件的响应者则安装有事件侦听器,针对某类事件进行侦听,当有此类事件传递至此时事件响应者就使用事件处理器来响应事件并决定事件是否可以继续传递。

示例:使用 WPF 内置路由事件

<Window x:Class="Demo4.Wpf路由事件.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:Demo4.Wpf路由事件"
  mc:Ignorable="d"
  Title="MainWindow" Height="450" Width="800">
  <Grid x:Name="grdRoot" Button.Click="AllButtonClicked">
    <Grid x:Name="grdSonRoot">
      <Grid.RowDefinitions>
        <RowDefinition/>
        <RowDefinition/>
      </Grid.RowDefinitions>
      <Canvas x:Name="canvasTop" Grid.Row="0">
        <Button x:Name="btnTop" Content="上方的按钮"/>
      </Canvas>
      <Canvas x:Name="canvasButtom" Grid.Row="1">
        <Button x:Name="btnButtom" Content="下方的按钮"/>
      </Canvas>
    </Grid>
  </Grid>
</Window>

image.png

namespace Demo4.Wpf路由事件 {
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window {
        public MainWindow() {
            InitializeComponent();

            //this.grdRoot.AddHandler(Button.ClickEvent, new RoutedEventHandler(AllButtonClicked));
        }

        private void AllButtonClicked(object sender, RoutedEventArgs e) {
            MessageBox.Show((e.OriginalSource as FrameworkElement).Name);
        }
    }
}

示例:自定义路由事件
创建自定义路由事件大体可以分为三个步骤:
(1)声明并注册路由事件。(2)为路由事件添加CLR事件包装。(3)创建可以激发路由事件的方法。

附加事件
image.png

标签:控件,Tree,事件,WPF,路由,响应者
From: https://www.cnblogs.com/swbna/p/17441690.html

相关文章

  • WPF命令(Command)
    本篇文章学习于:刘铁猛老师《深入浅出WPF》命令是什么?你可能会问:“有了路由事件为什么还需要命令系统呢?”事件的作用是发布、传播一些消息,消息送达接收者,事件的使命也就完成了,至于如何响应事件送来的消息事件并不做规定,每个接收者可以使用自己的行为来响应事件。也就是说,事件......
  • Wpf基础入门——XAML篇
    本篇文章学习于:刘铁猛老师《深入浅出WPF》什么是“项目模板”?最简单的WPF程序App.xamlMainWindow.xamlMainWindows.cs浅析用户界面的树型结构示例:在XAML中为对象属性赋值Attribute=Value形式例如:【不能设置太复杂的值】可以注意到在xaml文件中设置的value都是str......
  • Wpf基础入门——绑定(Binding)
    本篇文章学习于:刘铁猛老师《深入浅出WPF》Bing基础Binding更注重表达它是一种像桥梁一样的关联关系。WPF中,正是在这段桥梁上我们有机会为往来流通的数据做很多事情。如果把Binding比作数据的桥梁,那么它的两端分别是Binding的源(Source)和目标(Target)。一般情况下,Binding源是......
  • Wpf基础入门——资源(Resources)
    本篇文章学习于:刘铁猛老师《深入浅出WPF》WPF对象级资源每个WPF的界面元素都具有一个名为Resources的属性,这个属性继承自FrameworKElement类,其类型为ResourceDictionary。ResourceDictionary能够以“键一值”对的形式存储资源,当需要使用某个资源时,使用“键一值”对可以索引......
  • WPF概述
    文章来源:WindowsPresentationFoundation-WPF.NETFrameworkWPF概述WindowsPresentationFoundation(WPF)可以创建适用于Windows且具有非凡视觉效果的桌面客户端应用程序。WPF的核心是一个与分辨率无关且基于矢量的呈现引擎,旨在充分利用现代图形硬件。WPF通过一......
  • Wpf基础入门——控件介绍
    本篇文章学习于:刘铁猛老师《深入浅出WPF》控件到底是什么?WPF中是数据驱动UI,数据是核心、是主动的;UI从属于数据并表达数据、是被动的。Control是数据和行为的载体,而无需具有固定的形象。控件的派生关系如下:WPF的内容模型各类内容模型详解我们把符合某类内容模型的UI元......
  • Echarts 阴影点击事件获得当前柱状图的索引值方法
    Echarts阴影点击事件获得当前柱状图的索引值方法//什么在option外面的变量varclickIndex;option={//配置信息tooltip:{//提示框//提示触发类型:不触发trigger:'none',},//formatter回调函数,formatter:val=>{......
  • 【Azure 事件中心】如何查看Event Hub的生产者或者是消费者端的IP地址呢?
    问题描述哪些客户端IP正在向/从AzureEventHub发送/接收事件?如何来查看EventHub的生产者端,消费者端的IP地址呢? 问题解答如果需要查看EventHub服务端的日志,可以在Azure门户上开启诊断日志来查看。默认情况下,我们并不能看见EventHub的生产者,消费者端所使用的IP地址。在查看官......
  • 【Azure 事件中心】如何查看Event Hub的生产者或者是消费者端的IP地址呢?
    问题描述哪些客户端IP正在向/从AzureEventHub发送/接收事件?如何来查看EventHub的生产者端,消费者端的IP地址呢? 问题解答如果需要查看EventHub服务端的日志,可以在Azure门户上开启诊断日志来查看。默认情况下,我们并不能看见EventHub的生产者,消费者端所使用的IP地址。......
  • 考古笔记7:静态路由与联网(完整实验过程+爬坑记录)
    先上结论汇总配置过程:(无坑结论)爬坑历程拓扑配置R1:SW:PC侧验证问题1重启下交换机sw1;未解决,尝试端口重启;未解决尝试给SW1的vlan10和vlan20分配物理端口尝试f0/14连接一个host主机试试;连接的host不需要配置IP地址;重启SW1(似乎host开不开机都无所谓)删除f0/14和f0/15的Host;重启SW1解答看......