事件调度
UIElements监听来自操作系统或者脚本的事件,并使用EventDispatcher将这些事件分发给可视元素。事件调度程序为其发送的每个事件确定适当的调度策略。一旦确定,调度员就执行该策略。
可视元素和其他支持类,实现了某些事件的默认行为。某些情况下,这将涉及到创建和发送其它附加事件。例如,MouseMoveEvent可以生成额外的MouseEnterEvent和MouseLeaveEvent。这些附加事件将被放在队列中,并在当前事件完成后处理。例如,MouseMoveEvent将在处理MouseEnterEvent和MouseLeaveEvent事件之前完成。
事件目标(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 | ✔ | ✔ | ✔ |
本文深入解析UI事件调度机制,包括事件目标确定、事件传播、鼠标捕获、焦点环及Tab顺序控制等内容,揭示可视元素如何响应来自操作系统或脚本的事件。
221

被折叠的 条评论
为什么被折叠?



