WPF学习之路(四)路由

路由事件概述

功能定义:路由事件是一种可以针对元素树中的多个侦听器(而不是仅针对引发该事件的对象)调用处理程序的事件。

实现定义:路由事件是一个 CLR 事件,可以由RouteEvent 类的实例提供支持并由 Windows Presentation Foundation (WPF) 事件系统来处理。

实例:

Xaml

<Border Height="50" Width="300" BorderBrush="Gray" BorderThickness="1">
  <StackPanel Background="LightGray" Orientation="Horizontal" Button.Click="CommonClickHandler">
    <Button Name="YesButton" Width="Auto" >Yes</Button>
    <Button Name="NoButton" Width="Auto" >No</Button>
    <Button Name="CancelButton" Width="Auto" >Cancel</Button>
  </StackPanel>
</Border>

在这个简化的元素树中,Click事件的源是某个 Button元素,而所单击的 Button是有机会处理该事件的第一个元素。 但是,如果附加到 Button的任何处理程序均未作用于该事件,则该事件将向上冒泡到元素树中的 Button父级(即 StackPanel)。 该事件可能会冒泡到 Border,然后会到达元素树的页面根(未显示出来)。

换言之,此Click事件的事件路由为:Button-->StackPanel-->Border-->...

路由事件的策略

Bubbling:路由事件随后会路由到后续的父元素,直到到达元素树的根。

Direct:只有源元素本身才有机会调用处理程序以进行响应

Tunneling:最初将在元素树的根处调用事件处理程序。

路由事件策略会因为一下因素改变:

事件处理函数

public delegate void RoutedEventHandler(Object Sender, RoutedEventArgs e);
public delegate void MouseEventHandler(Object Sender, MouseEventArgs e);

RoutedEventArgs和MouseEventArgs包含路由事件的信息

如果设置"Handled"属性为True,路由事件会停止传递

类和实例事件处理函数

事件处理函数有两种类型,前一种是普通事件处理函数,"实例事件处理函数",另一种是通过EventManager.RegisterClassHandler方法将一个事件处理函数和类关联起来,"类事件处理函数",优先级更高

实例:(取自《葵花宝典--WPF自学手册》6.5)

自定义Button类

public class MySimpleButton : Button
{
    static MySimpleButton()
    {
        EventManager.RegisterClassHandler(typeof(MySimpleButton), CustomClickEvent, new RoutedEventHandler(CustomClickClassHandler), false);
    }

    public event EventHandler ClassHandlerProcessed;
    public static void CustomClickClassHandler(Object sender, RoutedEventArgs e)
    {
        MySimpleButton simpBtn = sender as MySimpleButton;
        EventArgs args = new EventArgs();
        simpBtn.ClassHandlerProcessed(simpBtn, e);
    }

    //Create and register routed event, routing strategies: Bubble
    public static readonly RoutedEvent CustomClickEvent = EventManager.RegisterRoutedEvent(
        "CustomClick",
        RoutingStrategy.Bubble,
        typeof(RoutedEventHandler),
        typeof(MySimpleButton));

    //CLR event wrapper
    public event RoutedEventHandler CustomClick
    {
        add { AddHandler(CustomClickEvent, value); }
        remove { RemoveHandler(CustomClickEvent, value); }
    }

    //Raise CustomClickEvent
    void RaiseCustomClickEvent()
    {
        RoutedEventArgs newEventArgs = new RoutedEventArgs(MySimpleButton.CustomClickEvent);
        RaiseEvent(newEventArgs);
    }

    //Onclick
    protected override void OnClick()
    {
        RaiseCustomClickEvent();
    }

}

MainWindow.xaml

<Window x:Class="Alex_WPFAPPDemo02.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:custom="clr-namespace:Alex_WPFAPPDemo02"
        custom:MySimpleButton.CustomClick="InsertList"
        Title="MainWindow" Height="350" Width="525">
    <Grid Margin="3" custom:MySimpleButton.CustomClick="InsertList" Name="Grid1">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <custom:MySimpleButton x:Name="simpBtn" CustomClick="InsertList">
            My Simple Button
        </custom:MySimpleButton>
        <ListBox Margin="5" Name="listBox" Grid.Row="1" />
        <CheckBox Margin="5" Grid.Row="2" Name="chkHandle">
            Handle first event
        </CheckBox>
        <Button Grid.Row="3" HorizontalAlignment="Right" Margin="5" Padding="3" Click="clear">
            Clear List
        </Button>
    </Grid>
</Window>

MainWindow.xaml.cs

protected int eventCounter = 0;
private void InsertList(object sender, RoutedEventArgs e)
{
    eventCounter++;
    string message = "#" + eventCounter.ToString() + ":\r\n"
        + "InsertList\r\n"
        + " Sender: " + sender.ToString() + "\r\n"
        + " Source: " + e.Source + "\r\n"
        + "Original Source: " + e.OriginalSource;
    listBox.Items.Add(message);
    e.Handled = (bool)chkHandle.IsChecked;
}

private void clear(object sender, RoutedEventArgs e)
{
    eventCounter = 0;
    listBox.Items.Clear();
}

添加类处理函数

static MySimpleButton()
{
    EventManager.RegisterClassHandler(typeof(MySimpleButton), CustomClickEvent, new RoutedEventHandler(CustomClickClassHandler), false);
}

public event EventHandler ClassHandlerProcessed;
public static void CustomClickClassHandler(Object sender, RoutedEventArgs e)
{
    MySimpleButton simpBtn = sender as MySimpleButton;
    EventArgs args = new EventArgs();
    simpBtn.ClassHandlerProcessed(simpBtn, e);
}

完善代码

public MainWindow()
{
    InitializeComponent();
    this.simpBtn.ClassHandlerProcessed += new EventHandler(ButtonRaisedClass);
}private void ButtonRaisedClass(object sender, EventArgs e)
{
    eventCounter++;
    string message = "#" + eventCounter.ToString() + ":\r\n"
        + "Windows Class Handler\r\n"
        + " Sender: " + sender.ToString();
    listBox.Items.Add(message);
}

private void ProcessHanldersToo(Object sender, RoutedEventArgs e)
{
    eventCounter++;
    string message = "#" + eventCounter.ToString() + ":\r\n"
        + "ProcessHanldersToo\r\n"
        + " Sender: " + sender.ToString()
        + " Source: " + e.Source + "\r\n"
        + "Original Source: " + e.OriginalSource;
    listBox.Items.Add(message);
}

private void Window_Loaded(object sender, RoutedEventArgs e)
{
    Grid1.AddHandler(MySimpleButton.CustomClickEvent, new RoutedEventHandler(ProcessHanldersToo), true);
}

可以查看路由事件的线路

To be continue...

时间: 2024-10-13 21:12:49

WPF学习之路(四)路由的相关文章

学习之路四十一丶简论重构

四月份的最后一天,写点心得,记录一下. 这个月一直忙着开发一个基于Win32 API的程序,大量运用了句柄等很多API的知识. 尤其随着代码量越来越大,逻辑越来越复杂,代码的清晰,健壮,扩展性成了一个需要重视的问题,也就是要适时的重构了. 一丶重构的时机 上个星期在修改一块重大逻辑的时候,需要修改很多代码,当时我犯了一个错误,一开始想了一个思路,但一上来没写多少就开始想着重构代码,目的是使其代码清晰以及可扩展. 可是随着时间的流失,不仅没有重构好,而且该改的逻辑也没有改好,我很郁闷,为什么会这样

【WPF学习】第四十四章 图画

原文:[WPF学习]第四十四章 图画 通过上一章的学习,Geometry抽象类表示形状或路径.Drawing抽象类扮演了互补的角色,它表示2D图画(Drawing)--换句话说,它包含了显示矢量图像或位图需要的所有信息. 尽管有几类画图类,但只有GeometryDrawing类能使用已经学习过的几何图形.它增加了决定如何绘制图形的画笔和填充细节.可将GeometryDrawing对象视为矢量插图中的形状.例如,可将标准的窗口元文件格式(.wmf)转换成准备插入用户界面的GeometryDrawi

Redis——学习之路四(初识主从配置)

首先我们配置一台master服务器,两台slave服务器.master服务器配置就是默认配置 端口为6379,添加就一个密码CeshiPassword,然后启动master服务器. 两台slave服务器配置如下: 1.先找到配置redis.windows-service.config文件修改port 6379 为port 6380 2.然后配置master服务器地址:slaveof 127.0.0.1 6379,然后主服务有密码还需要配置密码 masterauth CeshiPassword(本

【WPF学习】第四十三章 路径和几何图形

前面四章介绍了继承自Shape的类,包括Rectangle.Ellipse.Polygon以及Polyline.但还有一个继承自Shape的类尚未介绍,而且该类是到现在为止功能最强大的形状类,即Path类.Path类能够包含任何简单形状.多组形状以及更复杂的要素,如曲线. Path类提供了Data属性,该属性接受一个Geometry对象,该对象定义路径包含的一个或多个图形.不能直接创建Geometry对象,因为Geometry是抽象类,而且需要使用下表中列出的7个派生类的一个进行创建. 表 几何

WPF学习之路(八)页面

传统的应用程序中有两类应用程序模式:桌面应用,Web应用.WPF的导航应用程序模糊了这两类应用程序的界限的第三类应用程序 WPF导航表现为两种形式,一是将导航内容寄宿于窗口,二是XAML浏览器应用程序 四个核心要素:Page\HyperLink\NavigationServices\Journal Page WPF中的Page相比Window来说更加的精简,没有提供一个Show或者是Hide的方法,而是通过链接的方式进行页面切换.一般来说Page不设置自身的大小,因为页面的尺寸由包含它的宿主窗体

WPF学习之路(二) XAML(续)

属性 简单属性 前面用到的Width/Height都是简单属性,其赋值一定要放到双引号里 XAML解析器会根据属性的类型执行隐式转换 与C#的区别 SolidBrush.Color = Colors.AliceBlue; <Button Color = "AliceBlue" /> C#中有的枚举类型可以用(|)运算符组合,在XAML中用(,)分隔 附加属性 附加属性可以用于多个控件,但是在另外一个类中定义的属性,在WPF中常常用于布局 如DockPanel.Dock=&q

WPF学习之路(一) 初识WPF

参考<葵花宝典-WPF自学手册> VS2012 先创建第一个WPF小程序 1.创建WPF程序 2.查看Solution,WPF中xaml文件和cs文件经常成对出现 两个主要的类:APP(WPF主程序) MainWindow(程序主窗口) 3.添加Button和Click事件 MainWindow.xaml <Grid> <Button Content="Hello WPF" Margin="5" Click="Button_C

【WPF学习】第四十五章 可视化对象

前面几章介绍了处理适量适中的图形内容的最佳方法.通过使用几何图形.图画和路径,可以降低2D图形的开销.即使正在使用复杂的具有分层效果的组合形状和渐变画刷,这种方法也仍然能够正常得很好. 然而,这样设计不适合需要渲染大量图形元素的绘图密集型应用程序.例如绘图程序.演示粒子碰撞的物理模型程序或横向卷轴形式的游戏.这些应用程序面临的不是图形复杂程度的问题,而纯粹是单独的图形元素数量的问题.即使使用量级更轻的Geometry对象代替Path元素,需要的开销也仍会较大地影响应用程序的性能. WPF针对此类

[原创]java WEB学习笔记79:Hibernate学习之路--- 四种对象的状态,session核心方法:save()方法,persist()方法,get() 和 load() 方法,update()方法,saveOrUpdate() 方法,merge() 方法,delete() 方法,evict(),hibernate 调用存储过程,hibernate 与 触发器协同工作

本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱好者,互联网技术发烧友 微博:伊直都在0221 QQ:951226918 -----------------------------------------------------------------------------------------------------------------