• WPF路由事件


    理解路由事件

    事件路由允许源自某个元素的事件由另一个元素引发。

    定义、注册和包装路由事件

    public class MyWindow : Window
    {
    	/// <summary>
    	/// 定义和注册路由事件
    	/// </summary>
    	public static readonly RoutedEvent MyRoutedEvent = EventManager.RegisterRoutedEvent("MyEvent",
    		RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(MyWindow));
    
    	/// <summary>
    	/// 包装路由事件
    	/// </summary>
    	public event RoutedEventHandler MyRouted
    	{
    		add
    		{
    			base.AddHandler(MyRoutedEvent, value);
    		}
    		remove
    		{
    			base.RemoveHandler(MyRoutedEvent, value);
    		}
    	}
    }
    

    共享路由事件

    ​ 与依赖项属性一样,可以在类之间共享路由事件的定义。例如,两个基类UIElementContentElement类,都使用了MouseUp事件。MouseUp事件是在Windows.Input.Mouse类中定义,通过RoutedEvent.AddOwer()方法重用MouseUp事件。

    	UIElement.MouseUpEvent = Mouse.MouseUpEvent.AddOwner(Typeof(UIElement));
    

    触发路由事件

    路由事件的引发不是传统的.NET事件包装器引发,而是使用RaiseEvent()方法引发事件,说有UIElement类继承了该方法。

    	RoutedEventArgs e = new RoutedEventArgs(MyRoutedEvent, this);
    	base.RaiseEvent(e);
    

    处理路由事件

    XAML标记添加事件特性

    <local:MyWindow ... 
                    MyRouted="MyWindow_MyRouted"
                    ... />
    

    通过代码连接事件

         this.MyRouted += MainWindow_MyRouted;
    
    	///WPF事件参数类都是继承自RoutedEventArgs类,可自定义事件参数类来传递更多的信息
    	private void MainWindow_MyRouted(object sender, RoutedEventArgs e)
    	{
    		//do something...
    	}
    

    还可以通过调用AddHandler()方法链接事件处理器。

    	AddHandler(MyRoutedEvent, new RoutedEventHandler((s,e)=>
    	{
            //do something...                                                 
    	}));AddHandler(MyRoutedEvent, new RoutedEventHandler(Eventhandler));
    
    	private void Eventhandler(object o, RoutedEventArgs e)
    	{
    		//do something...
    	}
    	//使用RemoveHandler()方法来移除事件处理器 注:匿名委托不适用
    	//当程序多次附加事件处理器时,执行RemoveHandler()方法只删除一次连接。例如,连接了两次事件处理程序,删除了一次连接,触发事件时事件处理程序执行一次。		连接了三次事件处理程序,删除了一次连接,触发事件时事件处理程序执行两次。
    	RemoveHandler(MyRoutedEvent, new RoutedEventHandler(eventhandler));
    	或
         MyRouted -= Eventhandler;
    

    事件路由

    WPF窗体中的所有要素都一定程度上继承自UIElement类,WPF中的许多空间都是内容控件,继承自ContentControl,可以在其中多次重复嵌套。

    WPF路由事件模型的三种方式:

    • 直接路由事件(Direct Event):与.NET事件类似,它起源于一个元素,并且不传递给其他元素。例如,MouseEnter事件是一个直接路由事件。
    • 冒泡路由事件(Bubbling Event):在包含层次中向上传递。例如,MouseDown事件就是冒泡路由事件。冒泡顺序首先由被单击的元素引发,接下来被该元素的父元素引发,依次类推,直到WPF元素树的顶部为止。
    • 隧道路由事件(Tunneling Event):在包含层次中向下传递。隧道路由事件在事件到达恰当的控件之前为预览事件(或者可能终止事件)提供机会。例如,通过PreviewKeyDown事件可以截获是否按下了一个键,首先在窗口级别上,然后是更具体的容器,直到到达按下键时具有焦点的元素。

    路由事件的行为在注册路由事件的EventManager.RegisterEvent()中定义,传递为RoutingStrategy枚举值。

    RoutedEventArgs

    WPF事件参数类都是继承自RoutedEventArgs类,可自定义事件参数类来传递更多的信息。RoutedEventArgs类的属性:

    名称 说明
    Source 指示引发事件的对象。对于键盘事件,是当事件发生时具有焦点的控件。对于鼠标事件,是当事件发生时鼠标指针下面所有元素中最上面的元素。
    OriginalSource 指示最初是什么对象引发事件。通常OriginalSource属性和Source属性值是相同的。但是在某些情况下,OriginalSource属性指向对象树种更深得层次,以获得作为更高一级元素一部分的后台元素,事件最原始的源为Border元素,组成在控件模板中。
    RoutedEvent 通过事件处理程序为触发的事件提供RoutedEvent对象。如果使用同一事件处理程序处理不同的事件,这一信息是非常有用得。
    Handled 该属性允许终止事件的冒泡或隧道过程。如果一个控件将Handled属性设置为true,那么事件将不会继续传播。并且也不会再为任何其他元素引发该事件。

    冒泡路由事件

    <Label MouseUp="Label_MouseUp">
    	<Border MouseUp="Border_MouseUp">
    		<StackPanel MouseUp="StackPanel_MouseUp">
    			<Button Width="100" Height="30"  MouseUp="Button_MouseUp"/>
    		</StackPanel>
    	</Border>
    </Label>
    
    MessageBox.Show("btn"+"\n"+sender.ToString()+ "\n" + e.Source.ToString()+ "\n" + e.OriginalSource.ToString());
    

    在一个容器中放置下列元素,分别给每一个元素的MouseUp事件处理器添加以上代码。窗体打开后右键点击按钮就会依次弹出消息框,通过消息框信息可以看到事件的触发顺序依次是ButtonStackPanelBorderLabel。若在StackPanelMouseUp事件处理器中将e.Handled设置为true时,事件将不会继续传播,程序将不会在进入BoderLabel中的MouseUp事件处理器中。

    e.Handled = true;
    

    当事件处于挂起时,还可以通过AddHandler()方法,AddHandler()方法提供一个重载版本,在之前的基础上在传递一个bool类型的参数,将参数设置为true时,即使Handled属性被设置为true也可以接收到事件。

    lab.AddHandler(UIElement.MouseUpEvent, new MouseButtonEventHandler(Label_MouseUp), true);
    

    在设计器中删除Label元素的MouseUp事件特性,在初始化时通过以上代码连接事件处理器。当触发MouseUp时,Label消息框就会出现。

    附加事件

    <StackPanel Name="stpBtn" Grid.Row="2" ButtonBase.Click="DoSomething">
    	<Button Width="100" Height="30" />
    	<Button Width="100" Height="30" Margin="0,10" />
    	<Button Width="100" Height="30" />
    </StackPanel>
    

    以上代码在StackPanel元素中关联Button元素的点击事件,当点击其中按钮时就会进图DoSomething()方法,通过类名.事件命关联事件。Click事件是在ButtonBase中定义,Button继承自ButtonBase。附加事件还可以通过以下方式连接:

    //关联附加事件只能用UIElement.AddHandler()方法 不能用 += 运算符
    stpBtn.AddHandler(Button.ClickEvent, new RoutedEventHandler(DoSomething));
    

    隧道事件

    隧道路由事件的工作方式和冒泡路由事件相同,但方向相反。隧道路由事件一般有Preview开头,WPF通常成对的定义隧道路由事件通常和冒泡事件。如果将隧道路由事件标记为已处理过(e.Handled=true),那么就不会发生冒泡路由事件,这是因为两个事件共享RoutedEventArgs的同一个实例。

    WPF事件

    WPF元素提供了许多事件,但最重要的事件通常包括5类,生命周期事件、鼠标事件、键盘事件、手写笔事件、多点触控事件。

  • 相关阅读:
    SpringBoot实现支付宝沙箱
    nodejs一对一npm多版本安装
    【RocketMQ】消息的拉取
    朴实无华的三天每日一题
    java毕业设计菜篮子系统mybatis+源码+调试部署+系统+数据库+lw
    Python之初识GUI
    安全卸载Mac应用程序的方法,最后一种不会产生卸载残留
    SparkML
    C语言实现直接插入排序
    (附源码)springboot流浪动物救助系统 毕业设计 180920
  • 原文地址:https://www.cnblogs.com/wzmcnblogs/p/16198449.html