UIElements开发人员指南15 Dispatching Events(事件调度)

事件调度

UIElements监听来自操作系统或者脚本的事件,并使用EventDispatcher将这些事件分发给可视元素。事件调度程序为其发送的每个事件确定适当的调度策略。一旦确定,调度员就执行该策略。

可视元素和其他支持类,实现了某些事件的默认行为。某些情况下,这将涉及到创建和发送其它附加事件。例如,MouseMoveEvent可以生成额外的MouseEnterEventMouseLeaveEvent。这些附加事件将被放在队列中,并在当前事件完成后处理。例如,MouseMoveEvent将在处理MouseEnterEventMouseLeaveEvent事件之前完成。

事件目标(Event target

EventDispatcher.DispatchEvent()的首要任务是找到事件的目标。

这有时很容易,因为事件的target属性已设置。但是,对于源自操作系统的大多数事件而言,情况并非如此。

事件的目标依赖于事件类型。对于鼠标事件,目标通常是位于鼠标下方的最直接的可选元素。对于键盘事件,目标是处于当前焦点的元素。

找到目标后,会将其存储在EventBase.target中,在整个调度过程执行期间不会发生变化。Event.currentTarget将更新为当前正在处理的事件中的目标元素。

拾取模式和自定义形状

大多数鼠标事件使用拾取模式来确定其目标。在VisualElement类中有一个pickingMode属性,它支持下列值:

  • PickingMode.Position (默认值):根据定位矩形执行拾取。
  • PickingMode.Ignore:避免被鼠标事件选择为目标。

您可以覆盖VisualElement.ContainsPoint()方法来执行自定义的交互逻辑。

鼠标捕获

有时候,在鼠标按下之后,有的元素必须持续捕获鼠标位置,以确保后续所有鼠标事件都只发送给本元素,即使指针不再悬停在该元素上也是如此。例如某些控键(如:按钮,滑块或滚动条)需要依赖这样鼠标事件序列:MouseDown、MouseMove、MouseUp,此时就需要持续捕获鼠标位置。

要捕获鼠标,需要调用element.CaptureMouse()MouseCaptureController.CaptureMouse()

要释放鼠标,需要调用MouseCaptureController.ReleaseMouse()。如果另一个元素在您调用时已经捕获了鼠标CaptureMouse(),则该元素将接收MouseCaptureOutEvent 事件并将丢失鼠标捕获。

任意时刻,应用程序中只有一个元素可以捕获鼠标。一旦某个元素捕获鼠标,它将成为所有后续鼠标事件的目标,鼠标滚轮事件除外。注意:这仅适用于尚未设置目标的鼠标事件。

焦点环和Tab顺序

每个UIElement面板都有一个焦点环,用于定义元素的焦点顺序。默认情况下,通过在可视元素树上执行深度优先搜索(DFS depth-first search)来确定元素的焦点顺序。例如,下面描述的树的焦点顺序是F,B,A,D,C,E,G,I,H。

重点订单

焦点顺序

某些事件使用焦点顺序来确定哪个元素持有焦点。例如,键盘事件的目标是当前持有焦点的元素。

使用focusable属性可以控制元素是否可以获得焦点。默认情况下,VisualElements不可获得焦点,但默认情况下某些子类(例如TextField,可能是可以获得焦点的)。

使用tabIndex属性来控制焦点顺序,规则如下所示(tabIndex默认值为0):

  • 如果tabIndex为负数,则元素不可通过Tab获得焦点。
  • 如果tabIndex为零,则元素保持其默认Tab顺序,即由焦点环算法确定。
  • 如果tabIndex为正,则元素放在那些tabIndex为零或tabIndex值更高的元素前面{从小到达优先排列正值,后自动排列零值}。

事件传播

选择事件目标后,调度器计算事件的传播路径。传播路径是可以接收该事件的可视元素的有序列表。

从可视元素树的根开始,下降到目标,然后再上升到根来获得元素列表。

传播路径

传播路径

传播路径的第一阶段从根节点到达目标的父节点。这被称为涓滴阶段。{涓滴这个词来自于经济学术语“涓滴效应”}

传播路径的后一个阶段从目标父节点上升到根节点。这被称为冒泡阶段

事件目标位于传播路径的中间。

大多数事件类型都会发送给传播路径上的所有元素,某些事件类型会跳过冒泡阶段。此外,某些事件类型仅仅发送到事件目标。

如果某个元素被隐藏或禁用,则它不会接收事件。事件仍然会传播到隐藏或禁用元素的前辈节点和后辈节点。

当事件沿传播路径发送时,Event.currentTarget将更新为当前被处理事件的元素。这意味着在事件的回调函数中,Event.currentTarget是回调函数所注册的元素,而Event.target的是事件发生所在的元素。

事件类型的分发行为

每种事件类型都有自己的分发行为。下表每个事件类型的行为总结在三列中:

  • Trickles down(涓流):这种类型的事件在涓滴阶段被发送到元素。
  • Bubbles up(冒泡):这种类型的事件在冒泡阶段被发送到元素。
  • Cancellable(可取消):此类事件可以取消,停止或阻止其默认操作的执行。
  Trickles down Bubbles up Cancellable
MouseCaptureOutEvent  
MouseCaptureEvent  
ChangeEvent  
ValidateCommandEvent
ExecuteCommandEvent
DragExitedEvent  
DragUpdatedEvent
DragPerformEvent
DragEnterEvent    
DragLeaveEvent    
FocusOutEvent  
BlurEvent    
FocusInEvent  
FocusEvent    
InputEvent的  
KeyDownEvent
KeyUpEvent
GeometryChangedEvent      
MouseDownEvent
MouseUpEvent
MouseMoveEvent
ContextClickEvent
WheelEvent
MouseEnterEvent  
MouseLeaveEvent  
MouseEnterWindowEvent    
MouseLeaveWindowEvent    
MouseOverEvent
MouseOutEvent
ContextualMenuPopulateEvent
AttachToPanelEvent      
DetachFromPanelEvent      
TooltipEvent  
IMGUIEvent
发布了66 篇原创文章 · 获赞 158 · 访问量 17万+

猜你喜欢

转载自blog.csdn.net/AndrewFan/article/details/98732627