• 四,路由事件


    1. 定义、注册和包装路由事件
      WPF事件模型和属性模型非常类似,和依赖属性一样,路由属性由只读的静态字段表示,在一个静态构造函数中注册,并且通过一个标准的.Net事件定义进行包装。例如,WPF的Button类提供了熟悉的Click事件,该事件继承自ButtonBase基类。
      public abstract class ButtonBase : ContentControl
      {
          public static readonly RoutedEvent ClickEvent;
      
          static ButtonBase()
          {
              ButtonBase.ClickEvent = EventManager.RegisterRoutedEvent("Click", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(ButtonBase));
          }
      
          public event RoutedEventHandler Click
          {
              add
              {
                  base.AddHandler(ButtonBase.ClickEvent, value);
              }
              remove
              {
                  base.RemoveHandler(ButtonBase.ClickEvent, value);
              }
          }
      }
    2. 共享路由事件
      与依赖属性一样,可以在类之间共享路由事件的定义。例如,两个基类:UIElement类(该类的所有普通WPF元素的起点)和ContentElement类(该类是所有内容元素的起点),都使用了MouseUp事件。MouseUp事件是由System.Windows.Input.Mouse类定义的。UIElement类和ContentElement类只是通过RoutedEvent.AddOwner()方法重用MouseUp事件。
      UIElement.MouseUpEvent = Mouse.MouseUpEvent.AddOwner(typeof(UIElement));
    3. 引发路由事件
      路由事件不是通过传统的.Net事件包装器引发的,而是使用RaiseEvent()方法引发事件,所有元素都继承了该方法,下面是来自ButtonBase类深层的代码 :
      RoutedEventArgs e = new RoutedEventArgs(ButtonBase.MouseUpEvent, this);
      base.RaiseEvent(e);
    4. 使用多种方式为路由事件关联事件处理程序:
      1)  为XAML标记添加事件特性,如:<Image Source="happyface.jpg" Stretch="None" MouseUp="img_MouseUp" />
      2)  使用代码:img.MouseUp += new MouseButtonEventHandler(img_MouseUp);
      3)  通过UIElement.AddHandler()方法直接连接事件:img.AddHandler(Image.MouseUpEvent,new MouseButtonEventHandler(img_MouseUp));
    5. 事件路由
      WPF路由事件模型提供的路由事件的三种路由策略:
      1)  直接路由事件(Direct Event):它们起源于一个元素,并且不传递给其它元素,如MouseEnter事件是一个直接路由事件。
      2)  冒泡路由事件(Bubbling Event):如MouseDown事件是一个冒泡路由事件。它首先由被单击的元素引发,再被该元素的父元素引发,再被父元素的父元素引发,直接元素树的项部。
      3)  隧道路由事件(Tunneling Event):在包含层次中向下传递。
      QQ图片20140722213455
    6. 处理挂起事件的方法
      使用AddHandler()方法提供的一个重载版本,该重载版本可以接收一个Boolean值作为它的第三个参数,如果将该参数设置为true,哪么即使设置了Handled标志,也将接收到事件。通常这不是一个正确的设计决策,为了防止可能会造成的困惑,按钮被设计为会挂起MouseUp事件,因为如果为一个按钮错误地处理了MouseUp事件,而没有处理Click事件,那么事件处理代码就只能对鼠标单击做出响应,而不能对相应的键盘操作做出响应。
    7. 附加事件
      假设在StackPanel面板中包装了一堆按钮,并且希望在一个事件处理程序中处理所有这些按钮的单击事件,粗略的方法是将每个按钮的Click事件关联到同一个事件处理程序,但是Click事件支持事件冒泡,从而提供了一种更好的选择,可以通过以“类名.事件名”的形式把按钮的Click事件附加到更高层次的元素上(如包含按钮的StackPanel面板,它没有定义Click事件)来处理所有按钮的单击事件。如:
      <StackPanel Button.Click="DoSomething" Margin="5">
          <Button Name="btn1" Content="Command 1"></Button>
          <Button Name="btn2" Content="Command 2"></Button>
          <Button Name="btn3" Content="Command 3"></Button>
      </StackPanel>

      Click事件实际上是在ButtonBase类中定义的,且Button类继承了该事件,如果为ButtonBase.Click事件关联事件处理程序,那么当任何继承自ButtonBase的控件(包括Button类、RadioButton类以及CheckBox类)被单击时,都会调用该事件处理程序,如果只为Button事件关联事件处理程序,那么事件处理程序就只能被Button对象使用。
      可以在代码中关联附加事件,但是需要使用UIElement.AddHandler()方法,而不能使用+=运算符语法:

      StackPanelTest.AddHandler(Button.ClickEvent, new RoutedEventHandler(DoSomething));
    8. 隧道路由事件
      隧道路由事件的工作方式和冒泡路由事件相同,但方向相反,很容易识别隧道路由事件,因为它们都以单词Preview开头,而且,WPF通常成对地定义冒泡路由事件和隧道路由事件。这意味着如果发现一个冒泡的MouseUp事件,就还可以找到一个PreviewMouseUp隧道事件,隧道路由事件总是在冒泡路由事件之前触发。如果将隧道路由事件标记为已处理过,那么冒泡路由事件就不会发生,这是因为两个事件共享同一个RoutedEventArgs类的实例。

    9. 生命周期事件
      11
      FrameworkElement类实现了ISupportInitialize接口,该接口提供了两个用于控制初始化过程的方法,第一个是BiginInit()方法,在实例化元素后会立即调用该方法,BeginInit()方法被调用之后,XAML解析器设置所有元素的属性并添加内容。第二个是EndInit()方法,当初始化完成后,该方法被调用,此时引发Initialized事件。
      当创建窗口时,每个元素都以自下而上的方式被初始化,这意味着位于深层的嵌套元素在它们的容器之前先被初始化。当引发初始化事件时,可以确保元素树中当前元素以下的元素已经全部完成了初始化。但是包含当前元素的元素可能还没有初始化,并且不能假设窗口的任何其它部分已经初始化。在每个元素都已经初始化之后,还需要在它们的容器中进行布局、应用样式、绑定数据源。一旦初始化过程完成,就会引发Loaded事件,Loaded事件和Initialized事件发生的过程相反,也就是包含所有元素的窗口首先引发Loaded事件,然后才是更深层次的嵌套元素,当为所有元素都引发了Loaded事件之后,窗口就变的可见了,并且元素都已被呈现。
      224

    10. 输入事件
      输入事件是当用户使用某些种类的外设硬件进行交互时发生的事件,例如鼠标、键盘、手写笔或多点触摸屏。输入事件可以通过继承自InputEventArgs的自定义事件参数类传递额外的信息。InputEventArgs增加了两个属性:Timestamp和Device。Timestamp属性提供了一个指示事件何时发生的毫秒数。Device属性返回一个对象,该对象提供与触发事件的设备相关的更多信息。设备可以是鼠标、键盘、手写笔或多点触摸屏,它们由各自不同的类表示,所有这些类都继承自抽象类 System.Windows.Input.InputDevice
      八1
      当持续按下一个键的时候,会重复引发按键事件,此时KeyEventArgs.IsRepeat属性的值为true。
      可以使用KeyConverter类将Key值转换为更有用的字符串,例如:使用KeyConverter.ConverterToString()将Key.D9和Key.NumPad9都转换成字符串“9”。
      在进行文本框验证时最好的方法是同时处理PreviewTextInput事件(负责处理大多数验证)和PreviewKeyDown事件(用于哪些在文本框中不会引发PreviewTextInput的按键,如空格键),如:

      private void textBlock1_PreviewTextInput(object sender, TextCompositionEventArgs e)
      {
          short val;
          if (!Int16.TryParse(e.Text, out val))
          {
              e.Handled = true;
          }
      }
      
      private void textBlock1_PreviewKeyDown(object sender, KeyEventArgs e)
      {
          if (e.Key == Key.Space)
          {
              e.Handled = true;
          }
      }
      View Code
    11. 焦点
      为了让一个控件能够接受焦点,必须将Focusable属性设置为true,此属性是在UIElement类中定义的。
      为了将焦点从一个元素移动到另一个元素,用户可以单击鼠标或使用Tab键和箭头键,在以前的开发框架中,强制编程人员确保Tab键以合理方式移动焦点(通常是从左到右,从上到下),并且确保在窗口第一次显示时正确的控件获得焦点。在WPF中,而些额外的工作几乎不再需要,因为WPF使用层次结构的元素布局实现了Tab键切换焦点的顺序。当按下Tab键时会将焦点移动到当前元素的第一个子元素,如果当前元素没有子元素,会将焦点移动到同级的下一个子元素。例如:如果在具有两个StackPanel容器的窗口中使用Tab键转移焦点,焦点首先会通过第一个StackPanel面板中的所有控件,然后通过第二个容器中的所有控件。
      我们还可以通过TabIndex(TabIndex属性是在Control类中定义的,默认所有控件的TabIndex属性都被设置为Int32.MaxValue)控制Tab焦点转移的顺序,TabIndex为0的元素首先获得焦点,然后是1,2,3…。如果多个元素具有相同的的TabIndex值,WPF将使用自动顺序。
      可以通过将IsTabStop属性(此属性也是在Control类中定义)设置为false来阻止一个控件被包围进Tab键的焦点顺序。

    12. 获取键盘状态
      KeyEventArgs.KeyStates属性:反映触发事件的键的属性。
      KeyEventArgs.KeyboardDevice属性:它提供了KeyboardDivice类的一个实例,它的属性包括当前是哪个元素具有焦点(FocusedElement)以及当事件发生时按下了哪些修饰键,它还提供了同个简便的方法,对于这些方法,需要传递一个Key枚举值:
      QQ图片20140724210528
      可以使用KeyBoard类在非键盘事件中获取键盘状态信息,它与KeyboardDevice类非常类似,只是KeyBoard类由静态成员构成。

    13. 鼠标输入
      UIElement类定义了两个用于鼠标命中测试的属性:IsMouseOver(确定当前鼠标是否位于一个元素及其子元素的上面),IsMouseDirectlyOver(检查鼠标是否位于一个元素上面但是没有位于其子元素上面)。

    14. 多点触控输入
      多点触控(Multitouch)

  • 相关阅读:
    【查漏补缺】普通类中获取有注解的类
    【线程池原理】线程池的原理及实现
    【SpringCloud微服务实战学习系列】客户端负载均衡Spring Cloud Ribbon
    【SpringCloud错误】错误记录
    【SpringCloud微服务实战学习系列】服务治理Spring Cloud Eureka
    【SpringBoot整合Elasticsearch】SpringBoot整合ElasticSearch
    【SpringCloud微服务实战学习系列】配置详解
    【SpringCloud微服务实战学习系列】创建应用及解析
    【微服务系列】Spring SpringMVC SpringBoot SpringCloud概念、关系及区别
    【错误整理】ora-00054:resource busy and acquire with nowait specified解决方法【转】
  • 原文地址:https://www.cnblogs.com/jiao1855/p/3859224.html
Copyright © 2020-2023  润新知