Version: 2021.2
言語: 日本語
Dispatching events
Synthesizing events

イベントの処理

イベント処理順序

UI Toolkit のイベントは、HTML イベント に似ています。イベントが発生すると、ビジュアル要素ツリーの伝搬経路に沿って送信されます。イベントは対象となるビジュアル要素だけでなく、伝搬経路内のすべての要素に送信されます。

イベント処理の流れは以下の通りです。

  1. ルート要素からイベントターゲットの親までの要素にイベントコールバックを実行する。これはディスパッチプロセスの 下降段階 です。
  2. イベントターゲットでイベントコールバックを実行します。これはディスパッチ処理の ターゲット段階 です。
  3. イベントターゲットで ExecuteDefaultActionAtTarget() を呼び出します。
  4. イベントターゲットの親からルートまでの要素のイベントコールバックを実行します。これはディスパッチプロセスの 上昇段階 です。
  5. ExecuteDefaultAction() をイベントターゲット上で呼び出します。

イベントが伝搬経路を移動すると、Event.currentTarget プロパティは、現在そのイベントを処理する要素に更新されます。イベントコールバック関数内では、以下の通りです。

  • Event.currentTarget は、コールバックが登録されるビジュアル要素です。
  • Event.target は、元のイベントが発生するビジュアル要素です。

詳しくは、イベントのディスパッチ を参照してください。

イベントコールバックの登録

イベントコールバックを登録すると、テキストラベル上でマウスをクリックしたときの動作など、既存クラスの個々のインスタンスの動作をカスタマイズできます。

伝搬経路上の各要素 (ターゲットを除く) は、イベントを 2 回受け取ることができます。

  • 降下段階で 1 度。
  • 上昇段階で 1 度

デフォルトでは、登録されたコールバックは、ターゲットフェーズとバブルアップフェーズの間に実行されます。このデフォルトの動作により、親要素が子要素の後に反応するようになります。例えば、親要素が子要素より先に反応するようにしたい場合は、 TrickleDown.TrickleDown オプションでコールバックを登録します。

// 降下段階のコールバックを登録
myElement.RegisterCallback<MouseDownEvent>(MyCallback, TrickleDown.TrickleDown);

これは、ディスパッチャーに、ターゲット段階と降下段階でコールバックを実行するように通知します。

カスタム動作を特定のビジュアル要素に加えるには、イベントのコールバックを登録する必要があります。例えば、以下のコードは MouseDownEvent のコールバックを登録します。

// マウスダウンイベントのコールバックの登録
myElement.RegisterCallback<MouseDownEvent>(MyCallback);

コールバックの署名は以下のようになります。

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

1 つのイベントに対して複数のコールバックを登録することができます。同じコールバック関数を登録できるのは、同じイベントと同じプロパゲーションフェーズに 1 度だけです。VisualElement からコールバックを削除するには、myElement.UnregisterCallback() メソッドを呼び出します。

イベントコールバックへのカスタムデータの追加

イベントのコールバックと一緒にカスタムデータを送ることができます。カスタムデータを添付するには、呼び出しを拡張してコールバックを登録する必要があります。

以下のコードでは、MouseDownEvent のコールバックを登録し、カスタムデータをコールバック関数に送信しています。

// ユーザーデータをコールバックとともに送信
myElement.RegisterCallback<MouseDownEvent, MyType>(MyCallbackWithData, myData);

コールバック関数は、この署名を返します。

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

カスタムコントロールによるイベントへの応答

カスタムコントロールを実装している場合、UI Toolkit のイベントに 2 つの方法で応答することができます。

  • イベントコールバックの登録
  • デフォルトアクションの実装

イベントに対してどのように対応するかは、状況によって異なります。

コールバックとデフォルトアクションの違いは以下の通りです。

  • コールバックはクラスのインスタンスに登録する必要があります。デフォルトアクションは、クラスの仮想関数として実行されます。
  • コールバックは、伝搬経路上のすべてのビジュアル要素に対して実行されます。デフォルトのアクションは、イベントターゲットに対してのみ実行されます。
  • コールバックは、イベントに反応すべきかどうかを判断するために、追加確認を行う場合があります。例えば、マウスのクリックを処理するコールバックは、その要素がイベントのターゲットであるかどうかを確認する場合があります。デフォルトのアクションはこの手順を省略できます。
  • デフォルトアクションは伝搬段階でコールバックレジストリの検索を必要としないため、パフォーマンス面で若干有利です。

デフォルトアクションの実装

デフォルトアクションは、クラスのすべてのインスタンスに適用されます。デフォルトアクションを実装するクラスは、そのインスタンスにコールバックを登録することもできます。

クラスにデフォルトのアクションを実装する場合、VisualElement の新しいサブクラスを派生させ、ExecuteDefaultActionAtTarget() メソッドか ExecuteDefaultAction() メソッドのいずれか、または両方を実装する必要があります。

デフォルトアクションは、ビジュアル要素のサブクラスのインスタンスがイベントを受け取ったときに、各インスタンス上で実行されます。デフォルトアクションをカスタマイズするには、以下の例のように、 ExecuteDefaultActionAtTarget()ExecuteDefaultAction() をオーバーライドします。

override void ExecuteDefaultActionAtTarget(EventBase evt)
{
    // 基礎関数を呼び出す
    base.ExecuteDefaultActionAtTarget(evt);

    if (evt.GetEventTypeId() == MouseDownEvent.TypeId())
    {
        // ...
    }
    else if (evt.GetEventTypeId() == MouseUpEvent.TypeId())
    {
        // ...
    }
    // イベントタイプを追加
}

ExecuteDefaultAction() にデフォルトアクションを実装すると、デフォルトのアクションの実行を停止または防止できます。

ターゲットのデフォルトアクションを親のコールバックの前に実行したい場合は、デフォルトアクションを ExecuteDefaultActionAtTarget() に実装します。

デフォルトアクションは、あるタイプの要素がイベントを受け取ったときの動作と考える必要があります。例えば、チェックボックスは、クリックイベントに反応して、その状態を切り替えます。これを実行するには、すべてのチェックボックスにコールバックを登録するのではなく、デフォルトアクションの仮想関数をオーバーライドします。

カスタム制御の実践例

動作の実装

要素の動作をデフォルトの動作で実装する必要があります。インスタンスに接続されたコールバックで PreventDefault() を呼び出すことで、要素のデフォルトの動作をキャンセルすることができます。

動作をデフォルトアクションとして実装することによるその他の利点は以下の通りです。

  • デフォルトアクションが、コールバックレジストリのルックアップを必要としません。
  • コールバックのないインスタンスは伝搬プロセスに入りません。

柔軟性を高めるために、イベントのディスパッチ処理中にイベントターゲットのデフォルトのアクションを 2 か所で実行できます。

  1. 下降と上昇の伝播段階の間で、ターゲットコールバックの実行直後に、ExecuteDefaultActionsAtTarget() をオーバーライドします。
  2. イベントのディスパッチプロセスの最後に、ExecuteDefaultActions() をオーバーライドします。

クラスのデフォルトアクション

可能であれば ExecuteDefaultActions() にクラスのデフォルトアクションを実装してください。これにより、クラスをオーバーライドするためのオプションが増えます。PreventDefault() を呼び出して、イベント伝播プロセスの降下段階または上昇段階でクラスをオーバーライドすることができます。

イベントが親要素に伝搬してはいけない場合は、デフォルトアクション中にイベントの伝搬を停止する必要があります。例えば、テキストフィールドは KeyDownEvent を受け取って、その値を変更します。例えば、Delete キーでコンテンツを削除するように。このイベントは、親のビジュアル要素に伝播してはいけません。ExecuteDefaultActionsAtTarget() を使ってデフォルトアクションを実装し、StopPropagation() を呼び出して上昇段階でイベントが処理されないようにします。

デフォルトアクションは、イベントターゲットに対してのみ実行されます。クラスが子要素や親要素を対象としたイベントに反応するには、降下または上昇の伝搬段階で、イベントを受け取るコールバックを登録する必要があります。パフォーマンスを向上させるために、クラスにコールバックを登録することは避けてください。

イベント伝播の停止とデフォルトアクションのキャンセル

コールバックやデフォルトアクションの中でイベントを処理する場合、イベントの伝搬やデフォルトアクションの実行を停止することができます。例えば、親パネルは降下段階で伝搬を停止し、子パネルがイベントを受け取らないようにすることができます。

EventBase.PreDispatch()EventBase.PostDispatch() メソッドの実行は、イベントクラスの内部で防ぐことはできません。

以下のメソッドは、イベント伝播とデフォルトアクションに影響します。

StopImmediatePropagation()

  • イベントの伝搬プロセスを直ちに停止します。そのため、そのイベントに対する他のコールバックは実行されません。ただし、ExecuteDefaultActionAtTarget()ExecuteDefaultAction() のデフォルトアクションは引き続き実行されます。

StopPropagation()

  • 現在の要素の最後のコールバック後のイベント伝播プロセスを停止します。これにより、現在の要素のすべてのコールバックが確実に実行されますが、それ以降の要素はイベントに反応しません。ExecuteDefaultActionAtTarget()ExecuteDefaultAction() のデフォルトアクションだけは引き続き実行されます。

PreventDefaultAction()

  • イベント伝播プロセスが ExecuteDefaultActionAtTarget()ExecuteDefaultAction() のデフォルトアクションを呼び出すことを防ぎます。PreventDefaultAction() は、他のコールバックの実行を防ぐことはできず、上昇段階中に呼び出される ExecuteDefaultActionAtTarget() には効果がありません。

  • 2018–11–02 修正されたページ
Dispatching events
Synthesizing events