• 深入理解WPF路由事件


     WPF中有两种事件模型:一种是在WinForm时代就存在的CLR事件;另一种是WPF时代的路由事件;

    一、CLR事件定义与使用
      	//定义一个委托
        public delegate void ClickHandler(String Name);
         public class Test
        {
            /// 定义事件
            public event ClickHandler ClickEvent;
            /// <summary>
            /// 注册事件,事件绑定方法
            /// </summary>
            /// <param name="handler"></param>
            public void RegisterClickEventHandler(ClickHandler handler)
            {
                ClickEvent += handler;
            }
            /// 注销事件
            public void DeRegisterClickEventHandler(ClickHandler handler)
            {
                ClickEvent -= handler;
            }
            /// <summary>
            /// 触发事件
            /// </summary>
            /// <param name="UserName"></param>
            public void RaiseClickEvent(string UserName)
            {
                ClickEvent.BeginInvoke(UserName,null, null);
            }
        }
    
        public class TestEvent
        {
    
            public TestEvent()
            {
                Test test = new Test();
                test.RegisterClickEventHandler(On_Click);
                test.RegisterClickEventHandler(On_Click2);
                test.RaiseClickEvent("哈哈哈");
            }
    
            public void On_Click(String name)
            {
                Console.WriteLine(name);
            }
            public void On_Click2(String name)
            {
                Console.WriteLine(name+name);
            }
        }
    

    CLR事件特点
    1、事件发起者与接收者是紧密关联,不容易解耦
    2、如果利用事件传递消息,必须是逐级传递,不比繁琐,也不容易管理;

    二、路由事件
    
        public delegate void ClickHandler(String Name);
         public class Test:UIElement
        {
            public event ClickHandler ClickEvent;
            public void RegisterClickEventHandler(ClickHandler handler)
            {
                ClickEvent += handler;
            }
            public void DeRegisterClickEventHandler(ClickHandler handler)
            {
                ClickEvent -= handler;
            }
            /// <summary>
            /// 定义路由事件
            /// </summary>
            public static readonly RoutedEvent Click2Event = EventManager.RegisterRoutedEvent(
                    "Click2", RoutingStrategy.Direct, typeof(RoutedEventHandler), typeof(Test));
            /// <summary>
            /// 注册路由事件,绑定方法
            /// </summary>
            /// <param name="handler"></param>
            public void AddClick2EventHandler(RoutedEventHandler handler)
            {
                this.AddHandler(Click2Event, handler);
            }
            /// <summary>
            /// 注销路由事件
            /// </summary>
            /// <param name="handler"></param>
            public void RemoveClick2EventHandler(RoutedEventHandler handler)
            {
                this.RemoveHandler(Click2Event, handler);
            }
            public void RaiseClickEvent(string UserName)
            {
                //触发事件
                ClickEvent.BeginInvoke(UserName,null, null);
            }
           /// <summary>
           /// 触发路由事件
           /// </summary>
           /// <param name="UserName"></param>
            public void RaiseClick2Event(string UserName)
            {
                RoutedEventArgs args = new RoutedEventArgs(Click2Event, UserName);
                //触发事件
                this.RaiseEvent(args);
            }
        }
        public class TestEvent:UIElement
        {
            Test test = new Test();
            public TestEvent()
            {
                test.RegisterClickEventHandler(On_Click);
                this.AddHandler(Test.Click2Event, new RoutedEventHandler(On_Click2));
            }
            public void RaiseClick()
            {
                test.RaiseClick2Event("哈哈哈");
            }
            public void On_Click(String name)
            {
                Console.WriteLine(name);
            }
            public void On_Click2(object sender, RoutedEventArgs e)
            {
            }
        }
    

    为了方便XAML中进行事件绑定,我们修改下事件绑定的添加和删除,将两个方法合并为一个

            public event RoutedEventHandler Click2
            {
                add { this.AddHandler(Click2Event, value); }
                remove { this.RemoveHandler(Click2Event, value); }   
            }
    

    路由事件的特点:
     从路由事件的使用方式上看,路由事侦探同依赖属性性一样,也是由WPF中的基础类型(路由事件是:EventManager;依赖属性是DependencyProperty)统一管理,从而实现路由事件共享;

    • 1、定义事件
      声明为静态只读类型,以Event作为名称后缀; 并且是通过EventManager注册;
    • 2、绑定方法
      调用UIElement中的AddHandler; 相应的解绑,采用RemoveHanlder
    • 3、触发事件
      调用UIElement中的RaiseEvent方法触发;
    • 4、通过RoutedEventArgs参数,确定事件及参数。
    三、路由策略

     由于采用的是统一管理、统一绑定方法, 统一触发方式,所以路由事件的管理更加方便,事件传递也更加灵活;
     路由事件,之所以叫“路由”,最主要在于其事件传递的特殊性;在注册事件时,通过RoutingStrategy枚举,可以使用三种方式传递事件

    • RoutingStrategy.Direct
      与普通的.NET事件类似,只传递一层。它源自一个元素,并且不传递给其他元素。例如,MouseEnter事件(当鼠标移动到一个元素上面时触发)就是一个直接路由事件
    • RoutingStrategy.Bubble
      沿UI可视树往上传递。例如,MouseDown事件就是一个冒泡路由事件。它首先被单击的元素触发,接下来就是该元素的父元素触发,依此类推,直到WPF到达元素树的顶部为止
    • RoutingStrategy.Tunnel
      沿UI可视树往下传递,例如PreviewKeyDown就是一个隧道路由事件。在一个窗口上按下某个键,首先是窗口,然后是更具体的容器,直到到达按下键时具有焦点的元素
    四、关键事件传递的中断

     《深入浅出WPF》,以及《WPF高级编程》中都讲到当RoutedEventArgs 中Handler属性设置 true的时候,路由事件不再往下传递;其实设置Handled=true并不是终止事件的传阅,这只是为事件做一个标记而已,从业务上说明,无需再做其它处理;但是,事件还是会继续往下传递,只是处理方法是否会执行,得看我们调用UIElement.AddHandler(RoutedEvent, Delegate, Boolean)最后一个参数如何设置;
     MSDN解释如下:
    handledEventsToo Boolean
     如果为 true,则将按以下方式注册处理程序:即使路由事件在其事件数据中标记为已处理,也会调用处理程序;如果为 false,则使用默认条件注册处理程序,即当路由事件被标记为已处理时,将不调用处理程序。

  • 相关阅读:
    监测你的SQL SERVER让瓶颈暴露
    SQL Server日志文件总结及日志满的处理
    SQL保持多台服务器数据的一致性
    SAS的函数
    业务单号自动增长的处理办法
    有一点迷茫了
    怎么强制弹出窗口永远在最前面(转)
    XML技术上传文件
    SQL复制表结构的通用存储过程(转)
    ACCESS中使用SQL语句应注意的地方、与sql server的区别及几点技巧(整理中)
  • 原文地址:https://www.cnblogs.com/MonoHZ/p/14944169.html
Copyright © 2020-2023  润新知