Version: 2020.3
分发事件
合成事件

处理事件

事件处理顺序

Events in UI Toolkit are similar to HTML events. When an event occurs, it’s sent along the propagation path in the visual element tree. The event isn’t only sent to the target visual element, but to all elements within the propagation path.

The event handling sequence is as follows:

  1. Execute event callbacks on elements from the root element down to the parent of the event target. This is the trickle-down phase of the dispatch process. 2.在事件目标上执行事件回调。这是分发过程的目标阶段。 3.在事件目标上调用 ExecuteDefaultActionAtTarget()
  2. Execute event callbacks on elements from the event target parent up to the root. This is the bubble-up phase of the dispatch process. 5.在事件目标上调用 ExecuteDefaultAction()

在沿着传播路径发送事件时,Event.currentTarget 属性更新为当前正在处理事件的元素。在事件回调函数中:

  • Event.currentTarget 是回调注册的视觉元素。
  • Event.target 是原始事件发生的视觉元素。

有关更多信息,请参阅分发事件

对事件回调进行注册

通过注册事件回调,您可以自定义现有类的单个实例的行为,例如对鼠标单击文本标签做出反应。

传播路径上的每个元素(目标除外)对一个事件可以接收两次:

  • Once during the trickle-down phase.
  • 在冒泡阶段一次。

默认情况下,注册的回调会在目标阶段和冒泡阶段执行。此默认行为可确保父元素在其子元素之后做出反应。例如,如果您希望父元素在其子元素之前做出反应,请使用 TrickleDown.TrickleDown 选项注册回调:

// Register a callback for the trickle-down phase
myElement.RegisterCallback<MouseDownEvent>(MyCallback, TrickleDown.TrickleDown);

This informs the dispatcher to execute the callback at the target phase and the trickle-down phase.

要将自定义行为添加到特定的视觉元素,您必须在该元素上注册事件回调。例如,以下代码为 MouseDownEvent 注册一个回调:

// Register a callback on a mouse down event
myElement.RegisterCallback<MouseDownEvent>(MyCallback);

回调签名应如下所示:

void MyCallback(MouseDownEvent evt) { /* ...*/ }

You can register multiple callbacks for an event. You can only register the same callback function on the same event and propagation phase once. To remove a callback from a VisualElement, call the myElement.UnregisterCallback() method.

为事件回调添加自定义数据

您可以将自定义数据随同回调一起发送到事件。要附加自定义数据,您必须通过扩展该调用的方式来注册回调。

以下代码为 MouseDownEvent 注册一个回调并将自定义数据发送到回调函数:

//将用户数据一起发送到回调
myElement.RegisterCallback<MouseDownEvent, MyType>(MyCallbackWithData, myData);

回调函数应返回此签名:

void MyCallbackWithData(MouseDownEvent evt, MyType data) { /* ...*/ }

使用自定义控件响应事件

如果您要实现自定义控件,则可以通过两种方式响应 UI 工具包事件:

  • 注册事件回调。
  • 实现默认操作。

您选择如何响应事件取决于情况。

回调和默认操作之间的区别是:

  • 回调必须在类的实例上注册。默认操作作为类上的虚拟函数运行。
  • 回调在传播路径上的所有视觉元素都会执行。默认操作仅对事件目标执行。
  • 回调可能会执行额外的检查,以确定它们是否应该对事件做出反应。例如,处理鼠标单击的回调可能会检查元素是否是事件的目标。默认操作可以跳过此步骤。
  • 默认操作在性能上略有优势,因为它们在传播阶段不需要在回调注册表中查找。

实现默认操作

默认操作适用于该类的所有实例。实现默认操作的类也可以在该类的实例上注册回调。

When a class implements a default action, it must derive a new subclass of VisualElement and implement either the ExecuteDefaultActionAtTarget() method, the ExecuteDefaultAction() method, or both.

Default actions execute on each instance of a visual element sub-class when that instance receives an event. To customize default actions, you can override ExecuteDefaultActionAtTarget() and ExecuteDefaultAction(), as shown in the example below:

override void ExecuteDefaultActionAtTarget(EventBase evt)
{
    // Call the base function.
    base.ExecuteDefaultActionAtTarget(evt);

    if (evt.GetEventTypeId() == MouseDownEvent.TypeId())
    {
        // ...
    }
    else if (evt.GetEventTypeId() == MouseUpEvent.TypeId())
    {
        // ...
    }
    // More event types
}

通过在 ExecuteDefaultAction() 中实现您的默认操作,您可以停止或阻止一个默认操作的执行。

如果希望在父级回调之前执行目标默认操作,请在 `ExecuteDefaultActionAtTarget() 中实现默认操作。

You should view default actions as the behaviors that an element type should have when it receives an event. For example, a checkbox should toggle its state in response to a click event. To execute this, you can override a default action virtual function, instead of registering callbacks on all checkboxes.

自定义控件的最佳实践

实施行为

您应该通过具有默认操作的元素来实现行为。您可以在附加到实例的回调中调用 PreventDefault() 取消默认元素行为。

将行为实现为默认操作的其他好处是:

  • 默认操作不需要在回调注册表中查找。
  • 没有回调的实例不进入传播过程。

为了获得更大灵活性,可在事件分发过程中的以下两个时刻执行事件目标的默认操作:

  1. Between the trickle-down and the bubble-up propagation phase, immediately after execution of the target callbacks, override ExecuteDefaultActionsAtTarget().
  2. At the end of the event dispatch process, override ExecuteDefaultActions().

类的默认操作

Implement your class default actions in ExecuteDefaultActions(), if possible. This allows more options to override the class. You can call PreventDefault() to override the class during the trickle-down phase or the bubble-up phase of the event propagation process.

You must stop propagation of an event during a default action if the event shouldn’t propagate to the parent element. For example, a text field receives a KeyDownEvent that modifies its value, such as the Delete key to delete content. This event must not propagate to the parent visual element. Use ExecuteDefaultActionsAtTarget() to implement a default action, and call StopPropagation() to make sure the event isn’t processed during the bubble-up phase.

仅对事件目标执行默认操作。要使类对针对其子元素或父元素的事件做出反应,您必须注册回调以在涓流或冒泡传播阶段接收事件。避免在类中注册回调以提高性能。

停止事件传播并取消默认操作

When handling an event inside a callback or a default action, you can stop further event propagation and the execution of default actions. For example, a parent panel could stop propagation during the trickle-down phase to prevent its children from receiving events.

You can’t prevent the execution of the EventBase.PreDispatch() and EventBase.PostDispatch() methods inside the event class itself.

以下方法影响事件传播和默认操作:

StopImmediatePropagation()

  • 立即停止事件传播过程,因此不会为该事件执行其他回调。但是,ExecuteDefaultActionAtTarget()ExecuteDefaultAction() 默认操作仍然执行。

StopPropagation()

  • 在当前元素的上次回调后停止事件传播过程。这将确保当前元素的所有回调都得到执行,但是其他元素不会再对事件做出反应。ExecuteDefaultActionAtTarget()ExecuteDefaultAction() 默认操作仍然执行。

PreventDefaultAction()

  • Prevents the event propagation process from calling the ExecuteDefaultActionAtTarget() and ExecuteDefaultAction() default actions. PreventDefaultAction() doesn’t prevent the execution of other callbacks, and is ineffective on ExecuteDefaultActionAtTarget() when called during the bubble-up phase.

  • 2018–11–02 页面已修订
分发事件
合成事件