• WPF: RoutedEvent


    WPF中因为控件都是由其他控件组成的,也就形成了所谓的控件树。所以在事件处理上,与WinForms是不太一样的,它所采用的机制是所谓的RoutedEvent,即事件路由。

    注册路由事件时,我们可以选择不同的路由策略。

    • 管道传递(Tunneling): 事件首先在根元素上触发,然后向下层级传递,直到那个最初触发事件的子元素。
    • 冒泡(Bubbling): 事件从最初触发事件的子元素向根元素层级往上传递。
    • 直接(Direct): 事件仅在最初触发事件的子元素上触发。
    Window1.xaml

    <Window x:Class="Learn.WPF.Window1"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      Title="Window1">
      <Grid>
        <Border MouseRightButtonDown="MouseRightButtonDown">
          <StackPanel MouseRightButtonDown="MouseRightButtonDown">
            <Button MouseRightButtonDown="MouseRightButtonDown">Test</Button>
          </StackPanel>
        </Border>
      </Grid>
    </Window>

    Window1.xaml.cs

    public partial class Window1 : Window
    {
      public Window1()
      {
        InitializeComponent();
      }
      private void MouseRightButtonDown(object sender, MouseButtonEventArgs e)
      {
        MessageBox.Show((sender as Label).Name);
      }
    }

    在按钮上单击右键后,你会依次看到显示 "Button"、"StackPanel"、"Border" 的三个对话框,显然事件按照冒泡向根元素传递。
    有一点需要注意,WPF 路由事件参数有个 Handled 属性标记,一旦被某个程序标记为已处理,事件传递就会终止。测试一下。

    public partial class Window1 : Window
    {
      private void MouseRightButtonDown(object sender, MouseButtonEventArgs e)
      {
        MessageBox.Show(sender.GetType().Name);
        if (sender.GetType().Name == "StackPanel") e.Handled = true;
      }
    }

    很有效,Border.MouseRightButtonDown 不在有效。严格来说,事件并没有被终止,它依然会继续传递个上级或下级的元素,只是 WPF 没有触发事件代码而已。我们可以使用 AddHandler 方法重新注册一个新的事件处理方法,使得可以继续处理被终止的事件(注意: 如果事件没有终止,这会导致两次事件处理)。

    public partial class Window1 : Window
    {
      public Window1()
      {
        InitializeComponent();
        this.border1.AddHandler(Border.MouseRightButtonDownEvent,
          new MouseButtonEventHandler(MouseRightButtonDown), true);
      }
      private void MouseRightButtonDown(object sender, MouseButtonEventArgs e)
      {
        MessageBox.Show(sender.GetType().Name);
        if (sender.GetType().Name == "StackPanel") e.Handled = true;
      }
    }

    再运行试试,你会发现 Border.MouseRightButtonDown 被触发了。

    public void AddHandler(
      RoutedEvent routedEvent,
      Delegate handler,
      bool handledEventsToo
    )

    handledEventsToo: 如果为 true,则将按以下方式注册处理程序:即使路由事件在其事件数据中标记为已处理,也会调用该处理程序;如果为 false,则使用默认条件注册处理程序,即当路由事件被标记为已处理时,将不调用处理程序。
    通常情况下,WPF 控件会在管道事件的名称前添加 Preview 前缀。

    <Window x:Class="Learn.WPF.Window1"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      Title="Window1">
      <Grid>
        <Border PreviewMouseRightButtonDown="MouseRightButtonDown">
          <StackPanel PreviewMouseRightButtonDown="MouseRightButtonDown">
            <Button PreviewMouseRightButtonDown="MouseRightButtonDown">Test</Button>
          </StackPanel>
        </Border>
      </Grid>
    </Window>

    这回的输出结果正好跟前面的演示反过来,依次是 "Border"、"StackPanel"、"Button"。如果继续保留事件终止代码,那么 Button.PreviewMouseRightButtonDown 就不再被触发。

  • 相关阅读:
    移动开发 Native APP、Hybrid APP和Web APP介绍
    urllib与urllib2的学习总结(python2.7.X)
    fiddler及postman讲解
    接口测试基础
    UiAutomator2.0 和1.x 的区别
    adb shell am instrument 命令详解
    GT问题记录
    HDU 2492 Ping pong (树状数组)
    CF 567C Geometric Progression
    CF 545E Paths and Trees
  • 原文地址:https://www.cnblogs.com/chenxizhang/p/1649053.html
Copyright © 2020-2023  润新知