深入理解WPF路由事件

22 篇文章 2 订阅

 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 class Test:UIElement
    {
        /// <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);
        }
       /// <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.AddClick2EventHandler(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); }   
        }
原:test.AddClick2EventHandler(Test.Click2Event, new RoutedEventHandler(On_Click2));
改为:test.Click2=On_Click2;

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

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

注意事项:
路由事件是静态只读的
路由事件必须带Event后经缀;
路由事件的委托类型:RoutedEventHandler

三、路由策略

 由于采用的是统一管理、统一绑定方法, 统一触发方式,所以路由事件的管理更加方便,事件传递也更加灵活;
 路由事件,之所以叫“路由”,最主要在于其事件传递的特殊性;在注册事件时,通过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,则使用默认条件注册处理程序,即当路由事件被标记为已处理时,将不调用处理程序。

五、自定义事件参数

1)声明自定义参数,继承RoutedEventArgs

    public class ReportTimeArgs:RoutedEventArgs
    {
        public DateTime time;
        public ReportTimeArgs()
        {
            time = DateTime.Now;
        }
        public ReportTimeArgs(RoutedEvent name, Object source):base(name,source)
        {
            time = DateTime.Now;
        }
    }
  1. 定义事件时 事件的委托类型为: EventHandler<自定义参数类型>
        public static readonly RoutedEvent ReportTimeEvent = 
            EventManager.RegisterRoutedEvent("ReportTime", RoutingStrategy.Bubble,
            typeof(EventHandler<ReportTimeArgs>), typeof(ReportTimeButton));
        public event RoutedEventHandler ReportTime
        {
            add { AddHandler(ReportTimeEvent, value); }
            remove { RemoveHandler(ReportTimeEvent, value); }
        }

3)事件处理中参数由:RoutedEventArgs 改为 自定义参数类型

        private void Grid_ReportTime(object sender, ReportTimeArgs e)
        {
            Console.WriteLine((e.time.AddDays(3).ToString()));
            
        }
六、路由事件的使用

1、定义路由事件的类的实例, 处理路由事件:使用方法同CLR事件一致

2、非定义路由事件的类的实例,要处理中由事侦探:定义路由事件的类名.路由事件封装属性=事件处理方法

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

BoBPage

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值