精华内容
下载资源
问答
  • WPF 自定义路由事件

    2018-05-29 00:55:00
    WPF 自定义路由事件 原文:WPF 自定义路由事件WPF中的路由事件 as U know,和以前Windows消息事件区别不再多讲,这篇博文中,将首先回顾下WPF内置的路由事件的用法,然后在此基础上自定义一个路由事件...
    原文:WPF 自定义路由事件

    WPF中的路由事件 as U know,和以前Windows消息事件区别不再多讲,这篇博文中,将首先回顾下WPF内置的路由事件的用法,然后在此基础上自定义一个路由事件。

    1.WPF内置路由事件  

    WPF中的大多数事件都是路由事件,WPF有3中路由策略:

    具体不多讲,单需要注意的是WPF路由事件是沿着VIsualTree传递的。VisualTree与LogicalTree的区别在于:LogicalTree的叶子节点是构成用户界面的控件(xaml紧密相关),而VisualTree要连控件中的细微结构也算上。VisualTree是LogicalTree的扩展。

    reference: Understanding the Visual Tree and Logical Tree in WPF

    下面给出一个使用WPF内置路由事件的例子:

    <Window x:Class="WPFRoutedEvent.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="350" Width="525" >
        <Grid x:Name="Grid1" Margin="10" Background="AliceBlue"  MouseLeftButtonDown="Grid1_MouseLeftButtonDown">        
            <StackPanel Background="BurlyWood" Height="200" x:Name="StackPanel1" Button.Click="ButtonInStackPanel_Click"  MouseLeftButtonDown="StackPanel1_MouseLeftButtonDown">
                <Button x:Name="Button1" Content="RoutedEvent" Click="Button1_Click" />
            </StackPanel>
        </Grid>
    </Window>
    View Code
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Input;
    
    namespace WPFRoutedEvent
    {
        /// <summary>
        /// MainWindow.xaml 的交互逻辑
        /// </summary>
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
                //Grid订阅Button的Click事件
                Grid1.AddHandler(Button.ClickEvent, new RoutedEventHandler(ButtonInGrid_Click));
            }
    
            private void Button1_Click(object sender, RoutedEventArgs e)
            {
                MessageBox.Show("Button  Clicked.");
                //
                //e.Handled = true;
            }
    
            private void ButtonInStackPanel_Click(object sender, RoutedEventArgs e)
            {
                MessageBox.Show("StackPanel Clicked.");
            }
    
            private void ButtonInGrid_Click(object sender, RoutedEventArgs e)
            {
                MessageBox.Show("Grid Clicked.");
            }
    
            private void Grid1_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
            {
                MessageBox.Show("Grid Mouse Left button down.");
            }
    
            private void StackPanel1_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
            {
                MessageBox.Show("StackPanel Mouse Left button down.");
            }
        }
    }

    Button的Click事件是一个路由事件,分别在StackPanel中和Grid中订阅这个事件并进行相应的处理,分别用xaml代码和C#代码如下:

    Click="Button1_Click"
    Button.Click="ButtonInStackPanel_Click"
    Grid1.AddHandler(Button.ClickEvent, new RoutedEventHandler(ButtonInGrid_Click));

    StackPanel的MouseLeftButtonDown也是一个路由事件,也可以叫“附加事件”。其实“附加事件”也是路由事件,只是个文字游戏,为什么还要另外起个名字呢?原来路由事件的宿主都是那些拥有可视化实体的界面元素;而附加事件则不具备显示在用户界面上的能力。

    常见的附加事件有:

    Binding类:SourceUpdated事件、TargetUpdated事件。

    Mouse类:MouseEnter事件、MouseLeave事件、MouseDown事件、MouseUp事件等。

    Keyboard类:KeyDown事件、KeyUp事件等。

    Grid和StackPanel中均如下订阅:

    MouseLeftButtonDown="StackPanel1_MouseLeftButtonDown"

    程序运行如下:

     2.自定义路由事件    

     前面DebugLZQ写过一篇博文,内容是关于自定义CLR事件的,参考:.NET自定义事件小结下面来自定义一个WPF路由事件,各位博友可以比较下两者的异同。

    创建自定义路由事件大体可以分为三个步骤:

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

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

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

    下面我们自定义一个WPF路由事件,我们给事件携带个参数,为此需要创建一个RoutedEventArgs类的派生类。如下:

    using System;
    using System.Windows;
    
    namespace MyRoutedEvent
    {
        //事件参数
        class ReportTimeRoutedEventArgs:RoutedEventArgs
        {
            public ReportTimeRoutedEventArgs(RoutedEvent routedEvent, object source) : base(routedEvent, source) { }
    
            public DateTime ClickTime { get; set; }
        }
    }

    然后,创建一个Button类的派生类并按前面的步骤为其添加路由事件:

    using System;
    using System.Windows.Controls;
    using System.Windows;
    
    namespace MyRoutedEvent
    {
        class TimeButton:Button
        {
            //声明和注册路由事件\
            public static readonly RoutedEvent ReportTimeRoutedEvent =
                EventManager.RegisterRoutedEvent("ReportTime", RoutingStrategy.Bubble, typeof(EventHandler<ReportTimeRoutedEventArgs>), typeof(TimeButton));
            //CLR事件包装
            public event RoutedEventHandler ReportTime
            {
                add { this.AddHandler(ReportTimeRoutedEvent, value); }
                remove { this.RemoveHandler(ReportTimeRoutedEvent, value); }
            }
            //激发路由事件,借用Click事件的激发方法
    
            protected override void OnClick()
            {
                base.OnClick();//保证Button原有功能正常使用,Click事件被激发
    
                ReportTimeRoutedEventArgs args = new ReportTimeRoutedEventArgs(ReportTimeRoutedEvent, this);
                args.ClickTime = DateTime.Now;
                this.RaiseEvent(args);//UIElement及其派生类            
            }
    
        }
    }

    下面是程序界面的XAML代码,看下如何消费这个路由事件:

    <Window x:Class="MyRoutedEvent.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:local="clr-namespace:MyRoutedEvent" 
            Title="MainWindow" Height="350" Width="525">
        <Grid x:Name="grid1" local:TimeButton.ReportTime="TimeButton_ReportTime"><!---->
            <Grid x:Name="grid2">
                <Grid x:Name="grid3">
                    <StackPanel x:Name="stackPanel1">
                        <ListBox x:Name="listBox1"/>
                        <local:TimeButton Width="200" Height="200" Background="Aquamarine" ReportTime="TimeButton_ReportTime" /><!---->
                    </StackPanel>
                </Grid>
            </Grid>        
        </Grid>
    </Window>

    事件处理的后台代码如下:

    using System.Windows;
    
    namespace MyRoutedEvent
    {
        /// <summary>
        /// MainWindow.xaml 的交互逻辑
        /// </summary>
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
            }
    
            private void TimeButton_ReportTime(object sender, ReportTimeRoutedEventArgs e)//注意参数
            {
                listBox1.Items.Add(e.ClickTime.ToLongTimeString()+"DebugLZQ");
            }
        }
    }

    程序运行效果如下:

    小结:UIElement类是路由事件和附加事件的分水岭,因为从UIElement类开始才具备了再界面上显示的能力,也因为RaiseEvent、AddHandler和RemoveHandler这些方法也定义在UIElement类中。附加事件也只能算是路由事件的一种用法而不是一个新的概念,其本质还是路由事件。 

    posted on 2018-05-29 00:55 NET未来之路 阅读(...) 评论(...) 编辑 收藏

    转载于:https://www.cnblogs.com/lonelyxmas/p/9103121.html

    展开全文
  • WPF自定义路由事件

    千次阅读 2014-09-01 21:50:27
    本文通过实例演示WPF自定义路由事件的使用,进而探讨了路由事件与普通的CLR事件的区别(注:“普通的CLR事件”这个说法可能不太专业,但是,我暂时也找不到什么更好的称呼,就这么着吧,呵呵。)(扩展阅读:例说...

    一 概要

    本文通过实例演示WPF自定义路由事件的使用,进而探讨了路由事件与普通的CLR事件的区别(注:“普通的CLR事件”这个说法可能不太专业,但是,暂时也找不到什么更好的称呼,就这么着吧,呵呵。)(扩展阅读:例说.NET事件的使用)。

     

    二 实例演示与说明

    1 新建DetailReportEventArgs类,该类派生自RoutedEventArgs类,RoutedEventArgs类包含与路由事件相关的状态信息和事件数据。DetailReportEventArgs类中定义了属性EventTime和EventPublishr,EventTime属性记录事件的发生时间,而EventPublishr属性记录事件的发布者。

    DetailReportEventArgs类的详细代码如下所示,类文件为DetailReportEventArgs.cs。

    //************************************************************  
    //  
    // WPF路由事件示例代码  
    //  
    // Author:三五月儿  
    //   
    // Date:2014/08/31 
    //  
    // http://blog.csdn.net/yl2isoft  
    //  
    //************************************************************  
     
    using System;
    using System.Windows;
     
    namespace WpfRoutedEventExp
    {
        public class DetailReportEventArgs : RoutedEventArgs
        {
            public DetailReportEventArgs(RoutedEvent routedEvent, object source)
                :base(routedEvent,source){}
            public DateTime EventTime { get; set; }
            public string EventPublisher { get; set; }
        }
    }

    2 新建DetailReportButton类,该类派生自Button类,类中定义路由事件DetailReportEvent。

    DetailReportButton类的详细代码如下所示,类文件为DetailReportButton.cs。

    //************************************************************  
    //  
    // WPF路由事件示例代码  
    //  
    // Author:三五月儿  
    //   
    // Date:2014/08/31 
    //  
    // http://blog.csdn.net/yl2isoft  
    //  
    //************************************************************  
    using System;
    using System.Windows;
    using System.Windows.Controls;
     
    namespace WpfRoutedEventExp
    {
        public class DetailReportButton : Button
    {
             //定义路由事件
            public static readonly RoutedEvent DetailReportEvent = EventManager.RegisterRoutedEvent("DetailReport",RoutingStrategy.Bubble,typeof(EventHandler<DetailReportEventArgs>),typeof(DetailReportButton));
            //CLR事件包装
            public event RoutedEventHandler  DetailReport
            {
                add { this.AddHandler(DetailReportEvent, value); }
                remove { this.RemoveHandler(DetailReportEvent, value); }
            }
            //事件触发方法
            protected override void OnClick()
            {
                base.OnClick();
                DetailReportEventArgs args = new DetailReportEventArgs(DetailReportEvent, this);
                args.EventPublisher = this.ToString();
                args.EventTime = DateTime.Now;
                this.RaiseEvent(args);
            }
        }
    }

    下面将结合代码来学习WPF路由事件的定义方法。

    代码中先为类声明一个公共的(public)静态的(static)只读的(readonly)RoutedEvent类型的变量DetailReportEvent,然后使用EventManager类的RegisterRoutedEvent方法进行注册。

    (1)先来说说RoutedEvent类的RegisterRoutedEvent方法

    RoutedEvent类的RegisterRoutedEvent方法的定义如下所示:

    public static RoutedEvent RegisterRoutedEvent(string name, RoutingStrategy routingStrategy, Type handlerType, Type ownerType);

    从定义中可以看出,RegisterRoutedEvent方法接收四个参数,其中:

    • 第一个参数的类型为string,表示路由事件的名称,它必须和RoutedEvent类型变量的前缀一致。本例中RoutedEvent类型变量为DetailReportEvent,所以此处传入的name应该为DetailReport。
    • 第二个参数类型为RoutingStrategy,从字面意思就可以知道该参数表示路由事件的策略。WPF路由事件有3种路由策略:Bulle(冒泡式)、Tunnel(隧道式)和Direct(直达式),对于这三种策略在后面还会重点说明。此处先采用冒泡式,故传入参数为RoutingStrategy.Bubble。
    • 第三个参数与第四个参数的类型均为Type。其中:第三个参数指定事件处理器的类型,第四个参数指定路由事件的宿主类型。本例中的事件处理器类型为EventHandler<DetailReportEventArgs>,所以第三个传入参数为typeof(EventHandler<DetailReportEventArgs>)。路由事件的宿主为DetailReportButton 类,所以第四个传入参数为typeof(DetailReportButton)。

     (2)再来说说路由事件的触发方法OnClick

    路由事件的触发在OnClick方法中完成,方法中先实例化DetailReportEventArgs 类,得到对象args,并为args的EventPublisher与EventTime属性赋值,这样就创建了携带有路由事件相关信息的对象。然后调用 RaiseEvent方法把事件消息发送出去。

    (3)最后说说路由事件的CLR事件包装

    在我们的实例中,还为路由事件添加了CLR事件包装,这样一来,路由事件就被包装成一个普通的CLR事件,我们可以像使用普通的CLR事件一样来使用它。可以通过“+=”与“-=”操作符来订阅事件和取消事件的订阅操作。

     

    3 接下来,使用我们定义的DetailReportButton 类。

    下面是程序的主画面,是不是极其简单啊,仅包含一个DetailReportButton类型的按钮。

     

    图1 简洁的程序主画面

    程序主画面的完整代码如下所示。

    <Window x:Class="WpfRoutedEventExp.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:local="clr-namespace:WpfRoutedEventExp"
            Title="MainWindow" Height="350" Width="525">
        <Grid x:Name="Grid_FirstLayer" >
            <Grid x:Name="Grid_SecondLayer" >
                <Grid x:Name="Grid_ThirdLayer" >
                    <local:DetailReportButton x:Name="Button_Confirm" Width="100" Height="100" Content="Click Me" Margin="142,111,250,100" />
                </Grid>
            </Grid>
        </Grid>
    </Window>

    程序主画面的后端代码如下所示。

    //************************************************************  
    //  
    // WPF路由事件示例代码  
    //  
    // Author:三五月儿  
    //   
    // Date:2014/08/31 
    //  
    // http://blog.csdn.net/yl2isoft  
    //  
    //************************************************************ 
    using System.Windows;
     
    namespace WpfRoutedEventExp
    {
        /// <summary>
        /// MainWindow.xaml 的交互逻辑
        /// </summary>
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();            
                this.Grid_ThirdLayer.AddHandler(DetailReportButton.DetailReportEvent, new RoutedEventHandler(Button_Clicked1));
                this.Grid_SecondLayer.AddHandler(DetailReportButton.DetailReportEvent, new RoutedEventHandler(Button_Clicked1));
                this.Grid_FirstLayer.AddHandler(DetailReportButton.DetailReportEvent, new RoutedEventHandler(Button_Clicked1));
                this.Button_Confirm.AddHandler(DetailReportButton.DetailReportEvent, new RoutedEventHandler(Button_Clicked1));
            }
     
            private void Button_Clicked1(object sender, RoutedEventArgs e)
            {
                FrameworkElement ele = sender as FrameworkElement;
                DetailReportEventArgs dre = e as DetailReportEventArgs;
                MessageBox.Show(dre.EventPublisher + "-->" + ele.Name + ";" + dre.EventTime);
            }
        }
    }


    (1)我们的代码都干了些什么

    主画面的代码中先通过代码xmlns:local="clr-namespace:WpfRoutedEventExp"引入名称空间,再使用代码local:DetailReportButton来初始化DetailReportButton 类。

    主画面的后端代码中为控件Grid_ThirdLayer、Grid_SecondLayer、Grid_FirstLayer及Button_Confirm安装针对DetailReportButton的DetailReportEvent事件的侦听器,完成这个操作需要使用控件的AddHandler方法,该方法可以指定控件想侦听的事件,并将想侦听的事件与事件处理器关联起来。

    本例中所有控件使用相同的事件处理器Button_Clicked1方法,Button_Clicked1方法中输出事件的发布者、事件的响应者以及事件到达的时间等信息。

    程序的执行效果如下图所示。

     

    图2 路由事件DetailReportEvent的执行效果图1

    因为控件Button_Confirm、Grid_ThirdLayer、Grid_SecondLayer及Grid_FirstLayer均安装了针对DetailReportButton 的DetailReportEvent事件的侦听器,所以当路由事件DetailReportEvent到达Grid_ThirdLayer、Grid_SecondLayer、Grid_FirstLayer及Button_Confirm控件时都会被侦听到,进而执行事件处理方法Button_Clicked1,输出事件的发布者,此处为DetailReportButton,同时输出事件的侦听者,此处依次为Button_Confirm、Grid_ThirdLayer、Grid_SecondLayer及Grid_FirstLayer,并输出事件到达的时间。


    (2)对我们的程序再来做些小修改

    大家请看图2,注意事件到达的顺序,依次是Button_Confirm、Grid_ThirdLayer、Grid_SecondLayer及Grid_FirstLayer。

    下面我们可以做个小实验,修改路由事件的策略为Tunnel(隧道式),再次执行程序,得到图3所示的执行效果。

    给出执行效果前,先给出需要修改的代码:

    public static readonly RoutedEvent DetailReportEvent = EventManager.RegisterRoutedEvent("DetailReport",RoutingStrategy.Tunnel,typeof(EventHandler<DetailReportEventArgs>),typeof(DetailReportButton));

    图3 路由事件DetailReportEvent的执行效果图2

     此刻!请睁大你的双眼,注意图3中的红色椭圆框,被红色框选中的是事件的响应者,他们出现的顺序是:Grid_FirstLayer、Grid_SecondLayer、Grid_ThirdLayer及Button_Confirm。

    通过对比前后两次执行效果图,可以发现:当路由事件的路由策略被设置为Tunnel(隧道式)时,事件到达的顺序与将事件的路由策略设置为Bulle(冒泡式)时刚好相反。


    (3)还没完,接着修改我们的代码

    下面再看看将路由事件的路由策略修改为Direct(直达式)时的效果。

    需要修改的代码为:

    public static readonly RoutedEvent DetailReportEvent = EventManager.RegisterRoutedEvent("DetailReport",RoutingStrategy.Direct,typeof(EventHandler<DetailReportEventArgs>),typeof(DetailReportButton));

    再次执行程序的效果如图4所示。

     

    图4 路由事件DetailReportEvent的执行效果图3

    当路由事件的路由策略被设置为Direct(直达式)时,效果与CLR事件一样,直接将事件消息传送给事件处理器。


    (4)对路由事件的策略进行总结

    当路由事件的路由策略被设置为Bulle(冒泡式)时,路由事件的消息会从事件的触发者开始向它的上级容器控件一层一层的往外传,直至最外层的容器控件;而将事件的路由策略设置为Tunnel(隧道式)时,效果刚好与冒泡式相反,从最外层容器一层一层往内传;对于直达式就不用多说了吧。

     

    (5)该上主菜了吧,下面聊聊路由事件与普通CLR事件的区别

    通过学习前面的实例演示,我们完全可以总结出路由事件与普通的CLR事件的区别。

    普通的CLR事件通过事件订阅将事件的发布者与事件的订阅者紧密联系在一起,事件被触发时,事件发布者通过事件订阅将事件消息直接发送给事件订阅者,事件订阅者使用事件处理方法对事件的发生进行响应;而路由事件的发布者与响应者之间并不存在这种直接的订阅关系,事件的发布者只负责发布事件,而不用关心事件由谁来响应,因为事件发布者其实早就心知肚明,只有那些安装了事件侦听器的对象才会成为事件的响应者,至于谁愿意成为这个响应者他可不关心,而那些想侦听事件消息的对象只需要安装事件的侦听器,就可以侦听事件消息的达到,当事件消息到达时,使用事件处理方法进行响应。至于路由事件的消息采用何种方式来传递,取决于该路由事件采取何种路由策略。

     

    (6)路由事件的优点(既然存在,必有道理)

    降低了普通CLR事件中由于事件订阅而带来的耦合度。

     

    三 总结

    本文介绍了WPF自定义路由事件的使用方法,同时介绍了路由事件与传统CLR事件的区别以及路由事件的优点。

    展开全文
  • WPF 自定义路由事件简单实现 一、首先创建一个WPF项目,在项目中添加一个用户控件; 用户控件的xaml代码: <UserControl x:Class="WpfApp19.MyUserControl" xmlns=...

    WPF 自定义路由事件简单实现

    一、首先创建一个WPF项目,在项目中添加一个用户控件;
    用户控件的xaml代码:

    <UserControl x:Class="WpfApp19.MyUserControl"
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
                 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
                 xmlns:local="clr-namespace:WpfApp19"
                 mc:Ignorable="d" 
                 d:DesignHeight="120" d:DesignWidth="120">
        <Grid Background="AliceBlue">
            <Border BorderBrush="Green" BorderThickness="1"/>
            <StackPanel>
                <Button Name="btn_Test" Height="30" Width="100" Margin="0 10 0 10" Content="Test" Click="Btn_Test_Click"/>
                <TextBox Height="60" Width="100"/>
            </StackPanel>
        </Grid>
    </UserControl>
    

    后台代码,这里面已经定义好一个自定义路由事件,单击控件中的按钮会触发这个路由事件:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Shapes;
    
    namespace WpfApp19
    {
        /// <summary>
        /// MyUserControl.xaml 的交互逻辑
        /// </summary>
        public partial class MyUserControl : UserControl
        {
            public MyUserControl()
            {
                InitializeComponent();
            }
    
    
            //1、声明并注册路由事件,使用冒泡策略
            public static readonly RoutedEvent MyRountEvent = EventManager.RegisterRoutedEvent("MyRountEventHandler",
                RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(MyUserControl));
    
            //2、通过.NET事件包装路由事件
            public event RoutedEventHandler MyRountEventHandler
            {
                add
                {
                    AddHandler(MyRountEvent, value);
                }
                remove
                {
                    RemoveHandler(MyRountEvent, value);
                }
            }
    
            //3、使用按钮的单击事件激发路由事件
            private void Btn_Test_Click(object sender, RoutedEventArgs e)
            {
                RoutedEventArgs arg = new RoutedEventArgs();
                arg.RoutedEvent = MyRountEvent;
                RaiseEvent(arg);
            }
        }
    }
    

    自定义控件效果:
    在这里插入图片描述

    二、主窗体xaml代码:
    并启用自定义的路由事件;

    <Window x:Class="WpfApp19.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:WpfApp19"
            mc:Ignorable="d"
            Title="MainWindow" Height="450" Width="450">
        <Grid>
            <local:MyUserControl MyRountEventHandler="RouteEventControl_Click" Width="120" Height="120"></local:MyUserControl>
        </Grid>
    </Window>
    

    后台代码:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Shapes;
    
    namespace WpfApp19
    {
        /// <summary>
        /// MainWindow.xaml 的交互逻辑
        /// </summary>
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
            }
    
            private void RouteEventControl_Click(object sender, RoutedEventArgs e)
            {
                MessageBox.Show("Hello:" + e.Source.ToString());
            }
        }
    }
    

    运行效果:
    单击Test按钮,弹出提示。
    在这里插入图片描述

    展开全文
  • C#-wpf自定义路由事件

    2011-05-27 13:17:21
    自定义路由事件 尝试 自定义路由事件 尝试
  • using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows;..., RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(hh...
  • WPF中的路由事件 as U know,和以前Windows消息事件区别不再多讲,这篇博文中,将首先回顾下WPF内置的路由事件的用法,然后在此基础上自定义一个路由事件。 1.WPF内置路由事件 WPF中的大多数事件都是路由事件WPF...

    WPF中的路由事件 as U know,和以前Windows消息事件区别不再多讲,这篇博文中,将首先回顾下WPF内置的路由事件的用法,然后在此基础上自定义一个路由事件。

    1.WPF内置路由事件  

    WPF中的大多数事件都是路由事件,WPF有3中路由策略:

    具体不多讲,单需要注意的是WPF路由事件是沿着VIsualTree传递的。VisualTree与LogicalTree的区别在于:LogicalTree的叶子节点是构成用户界面的控件,而VisualTree要连控件中的细微结构也算上。VisualTree是LogicalTree的扩展。

    下面给出一个使用WPF内置路由事件的例子:

    <Window x:Class=WPFRoutedEvent.MainWindow
    xmlns
    =http://schemas.microsoft.com/winfx/2006/xaml/presentation
    xmlns:x
    =http://schemas.microsoft.com/winfx/2006/xaml
    Title
    =MainWindow Height=350 Width=525 >
    <Grid x:Name=Grid1 Margin=10 Background=AliceBlue MouseLeftButtonDown=Grid1_MouseLeftButtonDown> 
    <StackPanel Background=BurlyWood Height=200 x:Name=StackPanel1 Button.Click=ButtonInStackPanel_ClickMouseLeftButtonDown=StackPanel1_MouseLeftButtonDown>
    <Button x:Name=Button1 Content=RoutedEvent Click=Button1_Click />
    </StackPanel>
    </Grid>
    </Window>
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Input;

    namespace WPFRoutedEvent
    {
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
    public MainWindow()
    {
    InitializeComponent();
    //Grid订阅Button的Click事件
    Grid1.AddHandler(Button.ClickEvent, new RoutedEventHandler(ButtonInGrid_Click));
    }

    private void Button1_Click(object sender, RoutedEventArgs e)
    {
    MessageBox.Show(
    Button Clicked.);
    //
    //e.Handled = true;
    }

    private void ButtonInStackPanel_Click(object sender, RoutedEventArgs e)
    {
    MessageBox.Show(
    StackPanel Clicked.);
    }

    private void ButtonInGrid_Click(object sender, RoutedEventArgs e)
    {
    MessageBox.Show(
    Grid Clicked.);
    }

    private void Grid1_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
    MessageBox.Show(
    Grid Mouse Left button down.);
    }

    private void StackPanel1_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
    MessageBox.Show(
    StackPanel Mouse Left button down.);
    }
    }
    }

    Button的Click事件是一个路由事件,分别在StackPanel中和Grid中订阅这个事件并进行相应的处理,分别用xaml代码和C#代码如下:

    Click=Button1_Click
    Button.Click=ButtonInStackPanel_Click
    Grid1.AddHandler(Button.ClickEvent, new RoutedEventHandler(ButtonInGrid_Click));

    StackPanel的MouseLeftButtonDown也是一个路由事件,也可以叫“附加事件”。其实“附加事件”也是路由事件,只是个文字游戏,为什么还要另外起个名字呢?原来路由事件的宿主都是那些拥有可视化实体的界面元素;而附加事件则不具备显示在用户界面上的能力。

    常见的附加事件有:

    Binding类:SourceUpdated事件、TargetUpdated事件。

    Mouse类:MouseEnter事件、MouseLeave事件、MouseDown事件、MouseUp事件等。

    Keyboard类:KeyDown事件、KeyUp事件等。

    Grid和StackPanel中均如下订阅:

    MouseLeftButtonDown=StackPanel1_MouseLeftButtonDown

    程序运行如下:

     2.自定义路由事件    

     前面DebugLZQ写过一篇博文,内容是关于自定义CLR事件的。下面来自定义一个WPF路由事件,各位博友可以比较下两者的异同。

    创建自定义路由事件大体可以分为三个步骤:

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

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

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

    下面我们自定义一个WPF路由事件,我们给事件携带个参数,为此需要创建一个RoutedEventArgs类的派生类。如下:

    using System;
    using System.Windows;

    namespace MyRoutedEvent
    {
    //事件参数
    class ReportTimeRoutedEventArgs:RoutedEventArgs
    {
    public ReportTimeRoutedEventArgs(RoutedEvent routedEvent, object source) : base(routedEvent, source) { }

    public DateTime ClickTime { get; set; }
    }
    }

    然后,创建一个Button类的派生类并按前面的步骤为其添加路由事件:

    using System;
    using System.Windows.Controls;
    using System.Windows;

    namespace MyRoutedEvent
    {
    class TimeButton:Button
    {
    //声明和注册路由事件\
    public static readonly RoutedEvent ReportTimeRoutedEvent =
    EventManager.RegisterRoutedEvent(
    ReportTime, RoutingStrategy.Bubble, typeof(EventHandler<ReportTimeRoutedEventArgs>),typeof(TimeButton));
    //CLR事件包装
    public event RoutedEventHandler ReportTime
    {
    add { 
    this.AddHandler(ReportTimeRoutedEvent, value); }
    remove { 
    this.RemoveHandler(ReportTimeRoutedEvent, value); }
    }
    //激发路由事件,借用Click事件的激发方法

    protected override void OnClick()
    {
    base.OnClick();//保证Button原有功能正常使用,Click事件被激发

    ReportTimeRoutedEventArgs args 
    = new ReportTimeRoutedEventArgs(ReportTimeRoutedEvent, this);
    args.ClickTime 
    = DateTime.Now;
    this.RaiseEvent(args);//UIElement及其派生类 
    }

    }
    }

    下面是程序界面的XAML代码,看下如何消费这个路由事件:

    <Window x:Class=MyRoutedEvent.MainWindow
    xmlns
    =http://schemas.microsoft.com/winfx/2006/xaml/presentation
    xmlns:x
    =http://schemas.microsoft.com/winfx/2006/xaml
    xmlns:local
    =clr-namespace:MyRoutedEvent 
    Title
    =MainWindow Height=350 Width=525>
    <Grid x:Name=grid1 local:TimeButton.ReportTime=TimeButton_ReportTime><!—->
    <Grid x:Name=grid2>
    <Grid x:Name=grid3>
    <StackPanel x:Name=stackPanel1>
    <ListBox x:Name=listBox1/>
    <local:TimeButton Width=200 Height=200 Background=Aquamarine ReportTime=TimeButton_ReportTime /><!—->
    </StackPanel>
    </Grid>
    </Grid> 
    </Grid>
    </Window>

    事件处理的后台代码如下:

    using System.Windows;

    namespace MyRoutedEvent
    {
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
    public MainWindow()
    {
    InitializeComponent();
    }

    private void TimeButton_ReportTime(object sender, ReportTimeRoutedEventArgs e)//注意参数
    {
    listBox1.Items.Add(e.ClickTime.ToLongTimeString()
    +DebugLZQ);
    }
    }
    }

    程序运行效果如下:

    小结:UIElement类是路由事件和附加事件的分水岭,因为从UIElement类开始才具备了再界面上显示的能力,也因为RaiseEvent、AddHandler和RemoveHandler这些方法也定义在UIElement类中。附加事件也只能算是路由事件的一种用法而不是一个新的概念,其本质还是路由事件。

     

    文章来源:http://www.toolscreator.com/?p=1332

     

     

         路由事件还提供了更为丰富的功能。首先,路由事件允许软件开发人员通过EventManager.RegisterClassHandler()函数使用由类定义的静态处理程序。这个类定义的静态处理程序与类型的静态构造函数有些类似:在路由事件到达路由中的元素实例时,WPF都会首先调用该类处理程序,然后再执行该实例所注册的侦听函数。这种控件编写方式在WPF的内部实现中经常使用。另外,通过对路由事件进行管理的类型EventManager,我们可以通过函数调用GetRoutedEvents()得到相应的路由事件,而不再需要运用反射等较为耗时的方法。

      路由事件一般使用以下三种路由策略:1) 冒泡:由事件源向上传递一直到根元素。2) 直接:只有事件源才有机会响应事件。3) 隧道:从元素树的根部调用事件处理程序并依次向下深入直到事件源。一般情况下,WPF提供的输入事件都是以隧道/冒泡对实现的。隧道事件常常被称为Preview事件。

      您可能会想,路由事件的直接路由方式与普通CLR事件的处理方式有什么不同呢?实际上并没有什么不同。但是路由事件为WPF提供了更好的支持。例如触发器等功能需要事件是路由事件。同时路由事件还提供了类处理机制,从而为WPF提供了更灵活的执行方式。在后面的章节中,您将看到WPF是如何通过类处理函数完成一些WPF常见功能的。

    (或者可以这么解释:

    • 直接:只有源元素本身才有机会调用处理程序以进行响应。 这与 Windows 窗体用于事件的“路由”相似。 但是,与标准 CLR 事件不同的是,直接路由事件支持类处理(类处理将在下一节中介绍)而且可以由 EventSetter  EventTrigger 使用。

    )

     

     

    路由事件编程Example2

      与依赖项属性类似,WPF也为路由事件提供了WPF事件系统这一组成。为一个类型添加一个路由事件的方式与为类型添加依赖项属性的方法类似:软件开发人员需要通过EventManager的RegisterRoutedEvent()函数向事件系统注册路由事件。该函数的签名如下所示:

    复制代码
    1 public static RoutedEvent RegisterRoutedEvent(string name, RoutingStrategy routingStrategy, 
    2     Type handlerType, Type ownerType);
    复制代码

      该函数带有四个参数:第一个参数name表示事件在WPF事件系统中的名称,而第二个参数routingStrategy则标明了路由事件的路由原则。第三个参数handlerType用来标明事件处理函数的类型,而最后一个参数ownerType则用来标明拥有该路由事件的类型。例如,下面就是Control类注册MouseDoubleClick事件的代码:

    复制代码
    1 public static readonly RoutedEvent MouseDoubleClickEvent = 
    2     EventManager.RegisterRoutedEvent("MouseDoubleClick", RoutingStrategy.Direct, 
    3         typeof(MouseButtonEventHandler), typeof(Control));
    复制代码

      该函数返回一个RoutedEvent类型的实例。一般情况下,该实例将由一个public static readonly字段所保存,并可以通过add和remove访问符模拟为CLR事件。仍让我们以MouseDoubleClick事件为例。Control类中的MouseDoubleClick事件的实现如下所示:

    复制代码
     1 public event MouseButtonEventHandler MouseDoubleClick
     2 {
     3     add
     4     {
     5         base.AddHandler(MouseDoubleClickEvent, value);
     6     }
     7     remove
     8     {
     9         base.RemoveHandler(MouseDoubleClickEvent, value);
    10     }
    11 }
    复制代码

      在前面的讲解中我们已经提到过,EventManager类还提供了一个RegisterClassHandler()函数,以为特定路由事件注册类处理程序。该函数的原型如下所示:

    复制代码
    1 public static void RegisterClassHandler(Type classType, RoutedEvent routedEvent, 
    2     Delegate handler, bool handledEventsToo);
    复制代码

      该函数的第一个参数用来指定注册类处理函数的类型,而第二个参数则用来指定类处理函数所需要侦听的事件。第三个参数则指明了类处理函数,而将最后一个参数设置为true则允许类处理函数能够处理被标记为已处理的路由事件。

      由RegisterClassHandler()函数所注册的类处理程序可以在各个实例的事件处理程序运行之前运行。在该类处理程序中,软件开发人员可以选择将事件标记为已处理,或将当前事件转化为另一个事件。就仍以Control类的DoubleClick事件为例。Control类的静态构造函数通过RegisterClassHandler()函数首先注册了一个类处理程序:

    复制代码
    EventManager.RegisterClassHandler(typeof(Control), UIElement.MouseLeftButtonDownEvent, 
        new MouseButtonEventHandler(Control.HandleDoubleClick), true);
    复制代码

      接下来,在类处理程序HandleDoubleClick()中,其将会在用户双击时将MouseLeftButtonDown事件转化为双击事件:

    复制代码
     1 private static void HandleDoubleClick(object sender, MouseButtonEventArgs e)
     2 {
     3     if (e.ClickCount == 2) // 对双击进行处理
     4     {
     5         Control control = (Control)sender;
     6         MouseButtonEventArgs args = new MouseButtonEventArgs(e.MouseDevice, 
     7             e.Timestamp, e.ChangedButton, e.StylusDevice);
     8         if ((e.RoutedEvent == UIElement.PreviewMouseLeftButtonDownEvent) 
     9             || (e.RoutedEvent == UIElement.PreviewMouseRightButtonDownEvent))
    10         {
    11             args.RoutedEvent = PreviewMouseDoubleClickEvent;
    12             args.Source = e.OriginalSource;
    13             args.OverrideSource(e.Source); // 注意这里对Source的处理
    14             control.OnPreviewMouseDoubleClick(args); // 发出双击的Preview消息
    15         }
    16         else
    17         {
    18             args.RoutedEvent = MouseDoubleClickEvent;
    19             args.Source = e.OriginalSource;
    20             args.OverrideSource(e.Source);
    21             control.OnMouseDoubleClick(args); // 发出双击消息
    22         }
    23         if (args.Handled)
    24             e.Handled = true; // 将Handled设置为true,从而使该消息被隐藏
    25     }
    26 }
    复制代码

      需要注意的是,RegisterClassHandler()函数所注册的类处理函数需要是静态成员函数,因此您需要从参数中得到发出路由事件的类型实例。例如在上面的函数中,类处理函数就是通过参数sender得到实际发出路由事件的类型实例的。

      同时,上面的代码还向您展示了在组件编程过程中隐藏消息的方法及实现自定义输入事件的方法。在上面的代码中,路由事件的响应函数会手动发出双击的消息,从而使控件的PreviewDoubleClick以及DoubleClick事件被触发。接下来,路由事件的响应函数会将原事件的Handled属性设置为true,进而使原本的低级输入事件被隐藏。这种将低级事件隐藏并转化为高级事件的方法在WPF中非常常见。就以我们常用的Button类为例。在鼠标按下的时候,我们会接收到PreviewMouseDown事件,却不能接收到MouseDown事件。您一方面需要理解并掌握该方法,另一方面,您在遇到该情况时应能估计到产生该情况的原因,更能使用相应的解决方案:Preview-事件。

      除了通过RegisterRoutedEvent()函数之外,软件开发人员还可以通过RoutedEvent的AddOwner()函数将其它类型所定义的路由事件作为自身的路由事件。RoutedEvent的成员函数AddOwner()函数的原型如下:

    复制代码
    1 public RoutedEvent AddOwner(Type ownerType)
    复制代码

      该函数同样返回一个RoutedEvent实例并可以在CLR包装中使用。就以UIElement类所提供的MouseMove事件为例。WPF首先通过AddOwner()函数添加了对事件的引用:

    复制代码
    1 public static readonly RoutedEvent MouseMoveEvent = 
    2     Mouse.MouseMoveEvent.AddOwner(typeof(UIElement));
    复制代码

      接下来,您仍需要按照通常的方式为该附加事件添加一个CLR事件包装:

    复制代码
     1 public event MouseEventHandler MouseMove
     2 {
     3     add
     4     {
     5         this.AddHandler(Mouse.MouseMoveEvent, value, false);
     6     }
     7     remove
     8     {
     9         this.RemoveHandler(Mouse.MouseMoveEvent, value);
    10     }
    11 }
    复制代码

      最后要说的则是如何处理Handled已经被设置为true的路由事件。在需要处理这种类型事件的时候,您首先需要考虑的是,您当前的解决方案是否有略欠妥当的地方。如果您有足够强的理由证明自己对Handled属性已经被设置为true的路由事件的处理是有必要的,您需要通过AddHandler函数添加对路由事件的侦听,并在该函数调用中设置属性handledEventsToo参数的值为true。除此之外,软件开发人员还可以通过EventSetter中的HandledEventsToo属性实现相同的功能。

     

    附加事件

      和附加属性与依赖项属性之间的关系相对应,WPF的事件系统也支持普通的路由事件以及附加事件。与附加属性具有完全不同的语法实现不同,附加事件所使用的语法与普通的路由事件没有什么不同。例如,下面的代码中,对Image.MouseDown事件的使用就是对普通路由事件的使用:

    复制代码
    1 <StackPanel Image.MouseDown=…>
    复制代码

      而对Mouse.MouseDown事件的使用就是对附加路由事件的使用:

    复制代码
    1 <StackPanel Mouse.MouseDown=…>
    复制代码

      在上面的两段代码中,我们都使用了“类型名称.事件名称”的限定事件语法。但是它们一个属于普通的路由事件,一个是附加事件。那到底怎样辨别哪些是路由事件,哪些是附加事件呢。实际上,附加事件更主要的是其所具有的语义特征。与附加属性所拥有的服务特性类似,附加事件也常常对应着一个全局服务,例如Mouse类所对应的鼠标输入服务。这些服务可能并不会在XAML中作为当前元素的子元素存在。

      我们前面已经看到了,WPF的众多类型都通过AddOwner()函数调用等一系列方法将一些服务所提供的路由事件整合进类型定义中,例如UIElement类对Mouse类所提供的各个路由事件的集成。这常常是控件编写者所采用的一种控件编写策略。毕竟系统服务常常是较为低级的API。将其集成到类型中一方面可以直接使用该事件,而不是路由事件的限定形式,另一方面也令XAML对事件的表示更为直观。

      当然,您不要以为仅仅是输入等底层组成需要创建服务,其实在控件开发过程中,对这种服务的使用也是常常出现的。就以Selector为例。在您查看TreeViewItem,ListBoxItem等组成的实现时,您就会发现它们通过AddOwner()函数添加了对Selector.Selected事件的使用,而Selector自身则添加了对该事件的侦听,并最终转化为路由事件SelectionChanged。这是一个非常明显的对附加路由事件的使用。之所以将选中事件实现为一个服务则是因为对各个项目的选中操作常常发生在各个条目的内部,如鼠标的点击,因此在这些条目中处理选中事件并将该事件路由至Selector是一种较好的解决方法。

      那如何创建一个路由事件呢?答案就是为控件添加AddYourEventHandler()以及RemoveYourEventHandler()两个函数。这两个函数的第一个参数都需要标明需要操作的事件,事件的名称需要与YourEvent所代表的名称相匹配。而第二个参数则是需要为该附加事件指定的处理程序。就以Mouse类所提供的函数AddMouseDownHandler()以及RemoveMouseDownHandler()为例:

    复制代码
     1 public static void AddMouseDownHandler(DependencyObject element, 
     2     MouseButtonEventHandler handler)
     3 {
     4     UIElement.AddHandler(element, MouseDownEvent, handler);
     5 }
     6 
     7 public static void RemoveMouseDownHandler(DependencyObject element, 
     8     MouseButtonEventHandler handler)
     9 {
    10     UIElement.RemoveHandler(element, MouseDownEvent, handler);
    11 }
    复制代码

      这样,您就可以在XAML中通过Mouse.MouseDown引用Mouse类所提供的MouseDown附加事件了。

     

    转载请注明原文地址:http://www.cnblogs.com/loveis715/archive/2012/04/09/2439803.html

     

     

    附整个实例的代码:

    后台代码:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Shapes;
    
    namespace WpfApp2
    {
        /// <summary>
        /// MainWindow.xaml 的交互逻辑
        /// </summary>
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
            }
    
            private void TimeButton_ReportTime(object sender, ReportTimeRoutedEventArgs e)//注意参数
            {
                listBox1.Items.Add(e.ClickTime.ToString() + "   ---   " + sender.GetType().ToString());
            }
    
            private void FuncByAddOwner(object sender, RoutedEventArgs e)
            {
                listBox1.Items.Add("+++++++++++++++++++++  " + sender.GetType());
            }
        }
    
        //事件参数
        class ReportTimeRoutedEventArgs : RoutedEventArgs
        {
            public ReportTimeRoutedEventArgs(RoutedEvent routedEvent, object source) :
                base(routedEvent, source)
            {
            }
    
            public DateTime ClickTime { get; set; }
        }
    
        /// <summary>
        /// 自定义控件  路由事件一般为UIElement下的控件  可视化
        /// </summary>
        class TimeButton : Button
        {
            //声明和注册路由事件
            public static readonly RoutedEvent ReportTimeRoutedEvent =
            EventManager.RegisterRoutedEvent("ReportTime", RoutingStrategy.Bubble, typeof(EventHandler<ReportTimeRoutedEventArgs>), typeof(TimeButton));
            //CLR事件包装
            public event RoutedEventHandler ReportTime
            {
                add { this.AddHandler(ReportTimeRoutedEvent, value); }
                remove { this.RemoveHandler(ReportTimeRoutedEvent, value); }
            }
    
            #region 通过AddOwner方法 借用KnockButton的路由事件
    
            public static readonly RoutedEvent PreviewKnockEvent;
            public static readonly RoutedEvent KnockEvent;
    
            public event RoutedEventHandler Knock
            {
                add { this.AddHandler(KnockEvent, value); }
                remove { this.RemoveHandler(KnockEvent, value); }
            }
            public event RoutedEventHandler PreviewKnock
            {
                add { this.AddHandler(PreviewKnockEvent, value); }
                remove { this.RemoveHandler(PreviewKnockEvent, value); }
            }
    
            #endregion
    
            //激发路由事件,借用Click事件的激发方法
            protected override void OnClick()
            {
                base.OnClick();//保证Button原有功能正常使用,Click事件被激发
                ReportTimeRoutedEventArgs args = new ReportTimeRoutedEventArgs(ReportTimeRoutedEvent, this);
                //以下两个参数此程序无用,但在真实的项目中,使用前请赋值,保证参数无误
                args.RoutedEvent = ReportTimeRoutedEvent;
                args.Source = this;
                args.ClickTime = DateTime.Now;
                this.RaiseEvent(args);//UIElement及其派生类 
    
    
                //激发路由事件 自身拥有的每一个路由控件 都需要调用一下RaiseEvent方法
                RoutedEventArgs args2 = new RoutedEventArgs();
                args2.RoutedEvent = PreviewKnockEvent;
                args2.Source = this;
                this.RaiseEvent(args2);//UIElement及其派生类 
                args2.RoutedEvent = KnockEvent;
                args2.Source = this;
                this.RaiseEvent(args2);//UIElement及其派生类 
            }
    
            static TimeButton()
            {
                //添加类处理事件
                EventManager.RegisterClassHandler(typeof(TimeButton), Button.ClickEvent, new RoutedEventHandler(FirstRunFunc), true);
                //使用AddOwner方法将其他类型的路由事件作为自身的路由事件 example
                PreviewKnockEvent = KnockButton.PreviewKnockEvent.AddOwner(typeof(TimeButton));
                KnockEvent = KnockButton.KnockEvent.AddOwner(typeof(TimeButton));
            }
    
            //类处理程序 每次执行一次, 先于路由事件执行
            private static void FirstRunFunc(object sender, RoutedEventArgs e)
            {
                MessageBox.Show("First Run ?");
            }
        }
    
        /// <summary>
        /// 另一自定义控件 为TimeButton控件提供其路由事件KnockEvent 和 PreviewKnockEvent   --example
        /// </summary>
        class KnockButton : Button
        {
            public static readonly RoutedEvent PreviewKnockEvent;
            public static readonly RoutedEvent KnockEvent;
    
            static KnockButton()
            {
                PreviewKnockEvent = EventManager.RegisterRoutedEvent("PreviewKnock", RoutingStrategy.Tunnel, typeof(RoutedEventHandler), typeof(KnockButton));
                KnockEvent = EventManager.RegisterRoutedEvent("Knock", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(KnockButton));
            }
            public event RoutedEventHandler Knock
            {
                add { this.AddHandler(KnockEvent, value); }
                remove { this.RemoveHandler(KnockEvent, value); }
            }
            public event RoutedEventHandler PreviewKnock
            {
                add { this.AddHandler(PreviewKnockEvent, value); }
                remove { this.RemoveHandler(PreviewKnockEvent, value); }
            }
    
            //激发路由事件,借用Click事件的激发方法 (但此例由于没有触发KnockButton控件的Click方法,故此例此方法将不会被调用)
            protected override void OnClick()
            {
                RoutedEventArgs args = new RoutedEventArgs();
                args.RoutedEvent = PreviewKnockEvent;
                args.Source = this;
                this.RaiseEvent(args);//UIElement及其派生类 
                args.RoutedEvent = KnockEvent;
                args.Source = this;
                this.RaiseEvent(args);//UIElement及其派生类 
            }
        }
    }
    

     

    XAML代码:

    <Window x:Class="WpfApp2.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:local="clr-namespace:WpfApp2"
            Title="MainWindow" Width="500" Height="500" >
        <Grid  Name="grid" local:TimeButton.ReportTime="TimeButton_ReportTime" local:TimeButton.Knock="FuncByAddOwner">
            <Grid x:Name="grid2">
                <Grid x:Name="grid3">
                    <StackPanel x:Name="stackPanel1" >
                        <ListBox x:Name="listBox1" Height="300"/>
                        <local:TimeButton Width="100" Height="50" Content="TimeButton"  ReportTime="TimeButton_ReportTime"  Knock="FuncByAddOwner"/>
                    </StackPanel>
                </Grid>
            </Grid>
        </Grid>
    </Window>
    

     

     

    多谢网友的分享~ 多谢支持!

    转载于:https://www.cnblogs.com/luohengstudy/p/3270685.html

    展开全文
  • WPF中的路由事件 as U know,和以前Windows消息事件区别不再多讲,这篇博文中,将首先回顾下WPF内置的路由事件的用法,然后在此基础上自定义一个路由事件。 1.WPF内置路由事件  WPF中的大多数事件都是路由事件,...
  • WPF中的路由事件 as U know,和以前Windows消息事件区别不再多讲,这篇博文中,将首先回顾下WPF内置的路由事件的用法,然后在此基础上自定义一个路由事件。 1.WPF内置路由事件 WPF中的大多数事件都是路由事件,...
  • 首先自定义事件支持事件路由,需要使用 RegisterRoutedEvent 方法注册 RoutedEvent C#语法 public static RoutedEvent RegisterRoutedEvent( string name, RoutingStrategy routingStrategy, ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,906
精华内容 762
关键字:

wpf自定义路由事件