• WPF的路由事件、冒泡事件、隧道事件(预览事件)


    本文摘要:

    1:什么是路由事件;

    2:中断事件路由;

    3:自定义路由事件;

    4:为什么需要自定义路由事件;

    5:什么是冒泡事件和预览事件(隧道事件);

    1:什么是路由事件

        WPF中的事件为路由事件,所谓路由事件,MSDN定义如下:

        功能定义:路由事件是一种可以针对元素树中的多个侦听器(而不是仅针对引发该事件的对象)调用处理程序的事件。

        实现定义:路由事件是一个 CLR 事件,可以由 RoutedEvent 类的实例提供支持并由 Windows Presentation Foundation (WPF) 事件系统来处理。

        但这两类定义都比较抽象,我们来看更具体的定义:

           <Border Height="50" Width="250" BorderBrush="Gray" BorderThickness="1" >
                <StackPanel Background="LightGray" Orientation="Horizontal" MouseUp="StackPanel_MouseUp">
                    <TextBlock Name="YesTB" Width="50"  MouseUp="YesTB_MouseUp" Background="Blue" >Yes</TextBlock>
                </StackPanel>
            </Border>

        在这个例子中,事件的事件路由为:

    TextBlock -->StackPanel-->Border —>...

    2:中断事件路由      所有的路由事件都共享一个公共的事件数据基类 RoutedEventArgsRoutedEventArgs 定义了一个采用布尔值的 Handled 属性。 Handled 属性的目的在于,允许路由中的任何事件处理程序通过将 Handled 的值设置为 true 来将路由事件标记为“已处理”。

            private void StackPanel_MouseUp(object sender, MouseButtonEventArgs e)
            {
                MessageBox.Show("Panel");
            }
    
            private void YesTB_MouseUp(object sender, MouseButtonEventArgs e)
            {
                MessageBox.Show("button");
                e.Handled = true;
            }

        在上面的例子中,将不再触发StackPanel_MouseUp事件。

    3:自定义路由事件

          如下面的示例所示,首先使用 RegisterRoutedEvent 方法注册一个 RoutedEvent。按照约定,RoutedEvent 静态字段名称应当以后缀 Event 结束。在本示例中,事件的名称是 Tap,事件的路由策略是 Bubble。在注册调用之后,可以为该事件提供添加和移除公共语言运行时 (CLR) 事件访问器。

          请注意,尽管该事件在本特定示例中是通过 OnTap 虚方法引发的,但您引发事件的方式或者事件响应更改的方式取决于您的需要。

          还要注意,本示例主要实现 Button 的一整个子类;该子类是作为单独的程序集构建的,之后将在单独的可扩展应用程序标记语言 (XAML) 页上实例化为一个自定义类。这是为了说明这样一个概念:创建子类的控件可以插入到由其他控件组成的树中,在这种情况下,这些控件上的自定义事件具有与任何固有的 Windows Presentation Foundation (WPF) 元素完全相同的事件路由功能。

    public class MyButtonSimple: Button
    {
        // Create a custom routed event by first registering a RoutedEventID
        // This event uses the bubbling routing strategy
        public static readonly RoutedEvent TapEvent = EventManager.RegisterRoutedEvent(
            "Tap", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(MyButtonSimple));
    
        // Provide CLR accessors for the event
        public event RoutedEventHandler Tap
        {
                add { AddHandler(TapEvent, value); } 
                remove { RemoveHandler(TapEvent, value); }
        }
    
        // This method raises the Tap event
        void RaiseTapEvent()
        {
                RoutedEventArgs newEventArgs = new RoutedEventArgs(MyButtonSimple.TapEvent);
                RaiseEvent(newEventArgs);
        }
        // For demonstration purposes we raise the event when the MyButtonSimple is clicked
        protected override void OnClick()
        {
            RaiseTapEvent();
        }
    
    }
    <Window  
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:custom="clr-namespace:SDKSample;assembly=SDKSampleLibrary"
        x:Class="SDKSample.RoutedEventCustomApp"
    
        >
        <Window.Resources>
          <Style TargetType="{x:Type custom:MyButtonSimple}">
            <Setter Property="Height" Value="20"/>
            <Setter Property="Width" Value="250"/>
            <Setter Property="HorizontalAlignment" Value="Left"/>
            <Setter Property="Background" Value="#808080"/>
          </Style>
        </Window.Resources>
        <StackPanel Background="LightGray">
            <custom:MyButtonSimple Name="mybtnsimple" Tap="TapHandler">Click to see Tap custom event work</custom:MyButtonSimple>
        </StackPanel>
    </Window>

    4:为什么需要自定义路由事件

          一直到目前看来,我们都不太需要自定义的路由事件。但是,在我们创建自定义控制的时候,创建一些和业务相关的路由事件,就显得很有必要。

          如,创建一个在线考试中的题型展示控件,可以为该控件设计一个自定义事件,为“提交”。这样一来,这个题型控件不仅仅只有一些通用事件,还可以看上去更“业务”。

    5:什么是冒泡事件和预览事件(隧道事件)

     路由事件实际上分两类:冒泡事件和预览事件(隧道事件)。上文中的例子就是冒泡事件。

         冒泡事件是WPF路由事件中最为常见,它表示事件从源元素扩散(传播)到可视树,直到它被处理或到达根元素。这样您就可以针对源元素的上方层级对象处理事件。例如,您可向嵌入的 Grid 元素附加一个 Button.Click 处理程序,而不是直接将其附加到按钮本身。气泡事件有指示其操作的名称(例如,MouseDown)。

         隧道事件采用另一种方式,从根元素开始,向下遍历元素树,直到被处理或到达事件的源元素。这样上游元素就可以在事件到达源元素之前先行截取并进行处理。根据命名惯例,隧道事件带有前缀 Preview(例如 PreviewMouseDown)。

         在本文一开始的例子中,如果我们将MouseUP,改为PreviewMouseUP,效果会如何呢。

    区别:

         冒泡事件:在YesTB上点击,首先弹出“button”,再弹出“panel”。

         预览事件(隧道事件)事件:在YesTB上点击,首先弹出“panel”,再弹出“button”。

         看到了这点区别,那么我们加入e.Handled=true的时机也要不同。首先,

         冒泡事件例子中:e.Handled=true加在YesTB_PreviewMouseUp中,加入后,点击YesTB,将只弹出“button”。

         预览事件(隧道事件)例子中:e.Handled=true家在StackPanel_PreviewMouseUp中,加入后,点击YesTB,将只弹出“panel”。

  • 相关阅读:
    通过user-agent判断h5页面是在哪个手机App(QQ、微信、支付宝)下打开的
    vscode格式化插件
    简单直接,“NODE_ENV”总结
    NativeScript又一个Hybrid技术(附与Weex,ReactNative比较)
    ReactNative开发中遇到的问题记录
    两个在线编辑网站runjs和jsbin
    go 如何单测
    go语法-type等
    go语法-结构体和接口-细节
    解决 Webstorm 每次更新 Git 代码都要输入密码的问题
  • 原文地址:https://www.cnblogs.com/xietianjiao/p/6253082.html
Copyright © 2020-2023  润新知