博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
《WPF程序设计指南》读书笔记——第9章 路由输入事件
阅读量:7116 次
发布时间:2019-06-28

本文共 6010 字,大约阅读时间需要 20 分钟。

1.使用路由事件

    路由事件是一种可以针对元素树中的多个侦听器(而不是仅针对引发该事件的对象)调用处理程序的事件。通俗地说,路由事件会在可视树(逻辑树是其子集)上,上下routed,如果哪个节点上订阅了事件,就会被触发。

    路由事件的规则有三种:

    (1)冒泡;由事件源向上沿视觉树传递一直到根元素。如 MouseDown

    (2)直接;只有事件源才有机会响应事件,某个元素引发事件后,不传递到其他元素

    (3)隧道;从元素树的根部调用事件处理程序并依次向下深入直到事件源。 一般情况下,WPF提供的输入事件都是以隧道/冒泡对实现的。隧道事件常常被称为Preview事件。如 PreviewMouseDown

    可以通过 e.handled = true 来停止路由。

using System;using System.Windows;using System.Windows.Controls;using System.Windows.Input;using System.Windows.Media;using System.Windows.Documents;namespace LY.ExamineRoutedEvents{    public class ExamineRoutedEvents : Application    {        static readonly FontFamily fontfam = new FontFamily("宋体");        const string strformat = "{0,-30},{1,-15},{2,-15},{3,-15}";        StackPanel stackOutput;        DateTime dtLast;        [STAThread]        public static void Main()        {            ExamineRoutedEvents app = new ExamineRoutedEvents();            app.Run();        }        protected override void OnStartup(StartupEventArgs e)        {            base.OnStartup(e);            Window win = new Window();            win.Title = "Examine Routed Events";            //建立Grid            Grid grid = new Grid();            win.Content = grid;            //建立三行            RowDefinition rowdef = new RowDefinition();            rowdef.Height = GridLength.Auto;            grid.RowDefinitions.Add(rowdef);            rowdef = new RowDefinition();            rowdef.Height = GridLength.Auto;            grid.RowDefinitions.Add(rowdef);            rowdef = new RowDefinition();            rowdef.Height = new GridLength(100, GridUnitType.Star);            grid.RowDefinitions.Add(rowdef);            //建立button,加入到grid            Button btn = new Button();            btn.HorizontalAlignment = HorizontalAlignment.Center;            btn.Padding = new Thickness(24);            btn.Margin = new Thickness(24);            grid.Children.Add(btn);            //建立textblock,加入button            TextBlock text = new TextBlock();            text.FontSize = 24;            text.Text = win.Title;            btn.Content = text;            //建立标题,显示在ScrollViewer            TextBlock textHeadings = new TextBlock();            textHeadings.FontFamily = fontfam;            textHeadings.Inlines.Add(new Underline(new Run(string.Format(strformat,                "Routed Events", "Sender", "Source", "OriginalSource"))));            grid.Children.Add(textHeadings);            Grid.SetRow(textHeadings, 1);            //加入Scorllviewer            ScrollViewer scroll = new ScrollViewer();            grid.Children.Add(scroll);            Grid.SetRow(scroll, 2);            //建立Stackpanel,放入Scorllviewer            stackOutput = new StackPanel();            scroll.Content = stackOutput;            //新增事件处理器            UIElement[] els = { win, grid, btn, text };            foreach (UIElement el in els)            {                // Keyboard                el.PreviewKeyDown += AllPurposeEventHandler;                el.PreviewKeyUp += AllPurposeEventHandler;                el.PreviewTextInput += AllPurposeEventHandler;                el.KeyDown += AllPurposeEventHandler;                el.KeyUp += AllPurposeEventHandler;                el.TextInput += AllPurposeEventHandler;                // Mouse                el.MouseDown += AllPurposeEventHandler;                el.MouseUp += AllPurposeEventHandler;                el.PreviewMouseDown += AllPurposeEventHandler;                el.PreviewMouseUp += AllPurposeEventHandler;                                // Stylus                el.StylusDown += AllPurposeEventHandler;                el.StylusUp += AllPurposeEventHandler;                el.PreviewStylusDown += AllPurposeEventHandler;                el.PreviewStylusUp += AllPurposeEventHandler;                //Window,Grid,Textblock类没有click事件,所以用在ButtonBase类中定义的AddHandler方法                el.AddHandler(Button.ClickEvent,                    new RoutedEventHandler(AllPurposeEventHandler));                           }            win.Show();        }        void AllPurposeEventHandler(object sender, RoutedEventArgs e)        {            //如果有时间空隙,加入空格            DateTime dtNow = DateTime.Now;            if (dtNow - dtLast > TimeSpan.FromMilliseconds(100))                stackOutput.Children.Add(new TextBlock(new Run()));            dtLast = dtNow;            //显示事件信息            TextBlock text = new TextBlock();            text.FontFamily = fontfam;            text.Text = string.Format(strformat, e.RoutedEvent.Name,                TypeWithoutNamespace(sender),                 TypeWithoutNamespace(e.Source),                TypeWithoutNamespace(e.OriginalSource));            stackOutput.Children.Add(text);            (stackOutput.Parent as ScrollViewer).ScrollToBottom();        }        string TypeWithoutNamespace(object obj)        {            string[] str = obj.GetType().ToString().Split('.');            return str[str.Length-1];        }    }}

 2.自定义路由事件 

    (1)声明并注册路由事件

    (2)为路由事件添加CLR事件包装

    (3)创建可以激发路由事件的方法

    以ButtonBase类中定义的Click路由事件为例:

public abstract class ButtonBase : ContentControl, ICommandSource{    //字段 声明路由事件    public static readonly RoutedEvent ClickEvent;    //构造函数 在静态构造函数中注册路由事件,也可在直接申明字段同时注册路由事件    static ButtonBase()    {	//第1个参数为事件名	//第2个参数为路由策略,有三种策略:Bubble(冒泡式),Tunnel(隧道式),Direct(直达式)	//第3个参数为用于指定事件处理器的类型,该类型必须为委托类型,并且不能为 null	//第4个参数为路由事件所在的类名        ClickEvent = EventManager.RegisterRoutedEvent("Click", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(ButtonBase));    }    //事件 将路由事件包装成CLR事件    public event RoutedEventHandler Click    {        add { base.AddHandler(ClickEvent, value); }        remove { base.RemoveHandler(ClickEvent, value); }    }    //方法 创建激发事件的方法    protected virtual void OnClick()    {        RoutedEventArgs e = new RoutedEventArgs(ClickEvent, this);        base.RaiseEvent(e);    }}

  进一步可参考:http://www.cnblogs.com/wilderhorse/articles/3231454.html

     在进行上述自定义路由事件后,就可以像CLR事件一样,订阅事件和处理事件了。其中,订阅本身的事件同CLR事件一样,订阅子节点的事件用AddHandler方法,如上面“使用路由事件”中的例子。

 

转载于:https://www.cnblogs.com/pemp/p/3307332.html

你可能感兴趣的文章
线程池
查看>>
理解RESTful架构
查看>>
windows_learn 002 用户管理和组策略
查看>>
linux中的邮件服务器笔记
查看>>
linux命令:w、who、whoami、last、lastb、lastlog、basename、mail、hostname
查看>>
mysql常用备份还原命令
查看>>
Linux基础 文件的管理 正则表达式的应用的一些比较好的 练习
查看>>
九、LAMP的安装与配置
查看>>
wxWidgets第十五课 wxBitmap图片显示
查看>>
windows安装64位Pygame方法
查看>>
我在美国:当“洋教授”的甜酸苦辣(六)
查看>>
ScreenOS 原始IP访问MIP配置方法
查看>>
数据库笔记7:视图的作用
查看>>
8.1 shell介绍8.2 命令历史8.3 命令补全和别名8.4 通配符8.5 输入输出重定向
查看>>
bash配置文件读取顺序
查看>>
北京教育软件创业公司招 .net工程师
查看>>
AIX扩展文件系统
查看>>
RedHat 6 创建和扩容LVM卷
查看>>
access_log每周回滚方法分割一次成access_log.1....
查看>>
centos 6.5 ntp 服务器搭建
查看>>