UI Toolkit のイベントは、HTML イベント に似ています。イベントが発生すると、ビジュアル要素ツリーの伝搬経路に沿って送信されます。イベントは対象となるビジュアル要素だけでなく、伝搬経路内のすべての要素に送信されます。
イベント処理の流れは以下の通りです。
ExecuteDefaultActionAtTarget()
を呼び出します。ExecuteDefaultAction()
をイベントターゲット上で呼び出します。イベントが伝搬経路を移動すると、Event.currentTarget
プロパティは、現在そのイベントを処理する要素に更新されます。イベントコールバック関数内では、以下の通りです。
Event.currentTarget
は、コールバックが登録されるビジュアル要素です。Event.target
は、元のイベントが発生するビジュアル要素です。詳しくは、イベントのディスパッチ を参照してください。
イベントコールバックを登録すると、テキストラベル上でマウスをクリックしたときの動作など、既存クラスの個々のインスタンスの動作をカスタマイズできます。
伝搬経路上の各要素 (ターゲットを除く) は、イベントを 2 回受け取ることができます。
デフォルトでは、登録されたコールバックは、ターゲットフェーズとバブルアップフェーズの間に実行されます。このデフォルトの動作により、親要素が子要素の後に反応するようになります。例えば、親要素が子要素より先に反応するようにしたい場合は、 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 か所で実行できます。
ExecuteDefaultActionsAtTarget()
をオーバーライドします。ExecuteDefaultActions()
をオーバーライドします。可能であれば ExecuteDefaultActions()
にクラスのデフォルトアクションを実装してください。これにより、クラスをオーバーライドするためのオプションが増えます。PreventDefault()
を呼び出して、イベント伝播プロセスの降下段階または上昇段階でクラスをオーバーライドすることができます。
イベントが親要素に伝搬してはいけない場合は、デフォルトアクション中にイベントの伝搬を停止する必要があります。例えば、テキストフィールドは KeyDownEvent
を受け取って、その値を変更します。例えば、Delete
キーでコンテンツを削除するように。このイベントは、親のビジュアル要素に伝播してはいけません。ExecuteDefaultActionsAtTarget()
を使ってデフォルトアクションを実装し、StopPropagation()
を呼び出して上昇段階でイベントが処理されないようにします。
デフォルトアクションは、イベントターゲットに対してのみ実行されます。クラスが子要素や親要素を対象としたイベントに反応するには、降下または上昇の伝搬段階で、イベントを受け取るコールバックを登録する必要があります。パフォーマンスを向上させるために、クラスにコールバックを登録することは避けてください。
コールバックやデフォルトアクションの中でイベントを処理する場合、イベントの伝搬やデフォルトアクションの実行を停止することができます。例えば、親パネルは降下段階で伝搬を停止し、子パネルがイベントを受け取らないようにすることができます。
EventBase.PreDispatch()
と EventBase.PostDispatch()
メソッドの実行は、イベントクラスの内部で防ぐことはできません。
以下のメソッドは、イベント伝播とデフォルトアクションに影響します。
StopImmediatePropagation()
ExecuteDefaultActionAtTarget()
と ExecuteDefaultAction()
のデフォルトアクションは引き続き実行されます。StopPropagation()
ExecuteDefaultActionAtTarget()
と ExecuteDefaultAction()
のデフォルトアクションだけは引き続き実行されます。PreventDefaultAction()
ExecuteDefaultActionAtTarget()
と ExecuteDefaultAction()
のデフォルトアクションを呼び出すことを防ぎます。PreventDefaultAction()
は、他のコールバックの実行を防ぐことはできず、上昇段階中に呼び出される ExecuteDefaultActionAtTarget()
には効果がありません。