ASP.NET Core Blazor のイベント処理

注意

これは、この記事の最新バージョンではありません。 最新のバージョンに切り替えるには、目次の上部にある ASP.NET Core バージョン セレクターを使用します。

バージョン セレクター

セレクターが狭いブラウザー ウィンドウに表示されない場合は、ウィンドウの幅を広げるか、垂直省略記号 ([⋮]) >[目次] の順に選択します。

目次セレクター

この記事では、イベント引数の型、イベントのコールバック、既定のブラウザー イベントの管理など、Blazor のイベント処理機能について説明します。

次の @on{DOM EVENT}="{DELEGATE}"Razor 構文を使用して、Razor コンポーネント マークアップでデリゲート イベント ハンドラーを指定します。

イベント処理の場合:

  • Task を返す非同期デリゲート イベント ハンドラーがサポートされています。
  • デリゲート イベント ハンドラーによって UI レンダリングが自動的にトリガーされるため、StateHasChanged を手動で呼び出す必要はありません。
  • 例外がログされます。

コード例を次に示します。

  • UI 内でボタンが選択されたときに UpdateHeading メソッドを呼び出します。
  • UI 内でチェックボックスが変更されたときに CheckChanged メソッドを呼び出します。

Pages/EventHandlerExample1.razor:

@page "/event-handler-example-1"

<h1>@currentHeading</h1>

<p>
    <label>
        New title
        <input @bind="newHeading" />
    </label>
    <button @onclick="UpdateHeading">
        Update heading
    </button>
</p>

<p>
    <label>
        <input type="checkbox" @onchange="CheckChanged" />
        @checkedMessage
    </label>
</p>

@code {
    private string currentHeading = "Initial heading";
    private string? newHeading;
    private string checkedMessage = "Not changed yet";

    private void UpdateHeading()
    {
        currentHeading = $"{newHeading}!!!";
    }

    private void CheckChanged()
    {
        checkedMessage = $"Last changed at {DateTime.Now}";
    }
}

UpdateHeading は、以下の例では次のようになります。

  • ボタンが選択されると、非同期に呼び出されます。
  • 2 秒間待機してから、見出しを更新します。

Pages/EventHandlerExample2.razor:

@page "/event-handler-example-2"

<h1>@currentHeading</h1>

<p>
    <label>
        New title
        <input @bind="newHeading" />
    </label>
    <button @onclick="UpdateHeading">
        Update heading
    </button>
</p>

@code {
    private string currentHeading = "Initial heading";
    private string? newHeading;

    private async Task UpdateHeading()
    {
        await Task.Delay(2000);

        currentHeading = $"{newHeading}!!!";
    }
}

イベント引数

組み込みのイベント引数

イベント引数の型をサポートするイベントの場合、イベント メソッド定義でイベント パラメーターを指定する必要があるのは、イベントの型がメソッドで使用されている場合のみです。 次の例では、ReportPointerLocation メソッドで MouseEventArgs が使用されています。これにより、ユーザーが UI 内でボタンを選択すると、マウスの座標を報告するメッセージ テキストが設定されます。

Pages/EventHandlerExample3.razor:

@page "/event-handler-example-3"

@for (var i = 0; i < 4; i++)
{
    <p>
        <button @onclick="ReportPointerLocation">
            Where's my mouse pointer for this button?
        </button>
    </p>
}

<p>@mousePointerMessage</p>

@code {
    private string? mousePointerMessage;

    private void ReportPointerLocation(MouseEventArgs e)
    {
        mousePointerMessage = $"Mouse coordinates: {e.ScreenX}:{e.ScreenY}";
    }
}

サポートされている EventArgs を次の表に示します。

event クラス ドキュメント オブジェクト モデル (DOM) に関するメモ
クリップボードのトピック ClipboardEventArgs
ドラッグ DragEventArgs DataTransfer および DataTransferItem では、ドラッグされた項目データを保持します。

HTML ドラッグ アンド ドロップ API と共に JS 相互運用を使用し、Blazor アプリにドラッグ アンド ドロップを実装します。
エラー ErrorEventArgs
event EventArgs EventHandlers は、イベント名とイベント引数の型の間のマッピングを構成する属性を保持します。
フォーカス FocusEventArgs relatedTarget のサポートは含まれません。
入力 ChangeEventArgs
キーボード KeyboardEventArgs
マウス MouseEventArgs
マウス ポインター PointerEventArgs
マウス ホイール WheelEventArgs
進捗状況 ProgressEventArgs
Touch TouchEventArgs TouchPoint は、タッチを検知するデバイス上の単一接触点を表します。

詳細については、次のリソースを参照してください。

  • ASP.NET Core 参照ソース内の EventArgs クラス (dotnet/aspnetcore main ブランチ)

    注意

    通常、.NET 参照ソースへのドキュメント リンクを使用すると、リポジトリの既定のブランチが読み込まれます。このブランチは、.NET の次回リリースに向けて行われている現在の開発を表します。 特定のリリースのタグを選択するには、[Switch branches or tags](ブランチまたはタグの切り替え) ドロップダウン リストを使います。 詳細については、「ASP.NET Core ソース コードのバージョン タグを選択する方法」 (dotnet/AspNetCore.Docs #26205) を参照してください。

  • EventHandlers は、イベント名とイベント引数の型の間のマッピングを構成する属性を保持します。

カスタム イベント引数

Blazor ではカスタム イベント引数がサポートされています。このため、カスタム イベントを使用して任意のデータを .NET イベント ハンドラーに渡すことができます。

全般構成

カスタム イベント引数を使用したカスタム イベントは、一般に次の手順によって有効にされます。

  1. JavaScript では、ソース イベントからカスタム イベント引数オブジェクトをビルドするための関数を定義します。

    function eventArgsCreator(event) { 
      return {
        customProperty1: 'any value for property 1',
        customProperty2: event.srcElement.value
      };
    }
    
  2. カスタム イベントを、前述の JavaScript 初期化子のハンドラーに登録します。

    wwwroot/{PACKAGE ID/ASSEMBLY NAME}.lib.module.js:

    export function afterStarted(blazor) {
      blazor.registerCustomEventType('customevent', {
        createEventArgs: eventArgsCreator
      });
    }
    

    前述の例では、ファイル名の {PACKAGE ID/ASSEMBLY NAME} プレースホルダーは、アプリのパッケージ ID またはアセンブリ名を表します。

    Note

    registerCustomEventType の呼び出しは、1 つのイベントにつき 1 回だけスクリプト内で実行されます。

    registerCustomEventType の呼び出しには、afterStarted によって提供される blazor パラメーター (b は小文字) を使用します。 Blazor オブジェクト (B は大文字) を使用しても登録は有効ですが、パラメーターを使用することをお勧めします。

  3. イベント引数のクラスは次のように定義します。

    namespace BlazorSample.CustomEvents;
    
    public class CustomEventArgs : EventArgs
    {
        public string? CustomProperty1 {get; set;}
        public string? CustomProperty2 {get; set;}
    }
    
  4. カスタム イベントに関する EventHandlerAttribute 属性注釈を追加することによって、イベント引数を使用したカスタム イベントを接続します。

    • コンパイラで [EventHandler] クラスを検出できるようにするには、C# クラス ファイル (.cs) に配置し、通常の最上位クラスにする必要があります。
    • クラスに public とマークを付けます。
    • このクラスにメンバーは必要ありません。
    • このクラスは、Razor コンパイラで検出できるように "EventHandlers" という名前にする "必要があります"。
    • クラスをアプリに固有の名前空間の下に配置します。
    • イベントが使用される Razor コンポーネント (.razor) に名前空間をインポートします。
    using Microsoft.AspNetCore.Components;
    
    namespace BlazorSample.CustomEvents;
    
    [EventHandler("oncustomevent", typeof(CustomEventArgs), enableStopPropagation: true, enablePreventDefault: true)]
    public static class EventHandlers
    {
    }
    
  5. 1 つまたは複数の HTML 要素に対してイベント ハンドラーを登録します。 デリゲート ハンドラー メソッドで JavaScript から渡されたデータにアクセスします。

    @using namespace BlazorSample.CustomEvents
    
    <button @oncustomevent="HandleCustomEvent">Handle</button>
    
    @code
    {
        private void HandleCustomEvent(CustomEventArgs eventArgs)
        {
            // eventArgs.CustomProperty1
            // eventArgs.CustomProperty2
        }
    }
    

@oncustomevent 属性が IntelliSense によって認識されない場合は、コンポーネントまたは _Imports.razor ファイルに、EventHandler クラスを含む名前空間の @using ステートメントが必ず含まれるようにしてください。

DOM 上でカスタム イベントが発生するたびに、JavaScript から渡されたデータを使用してイベント ハンドラーが呼び出されます。

カスタム イベントを発生させようとしている場合は、bubbles を有効にするために、その値を true に設定する必要があります。 それを行わない場合は、イベントが発生しても、処理用の Blazor ハンドラーが C# カスタム EventHandlerAttribute メソッドに到達することはありません。 詳細については、「MDN Web Docs: イベントのバブリング」を参照してください。

カスタム クリップボードの貼り付けイベントの例

次の例では、貼り付けの時刻とユーザーが貼り付けたテキストを含む、カスタム クリップボードの貼り付けイベントを受け取ります。

イベントのカスタム名 (oncustompaste) と、このイベントのイベント引数を保持する .NET クラス (CustomPasteEventArgs) を宣言します。

CustomEvents.cs:

using Microsoft.AspNetCore.Components;

namespace BlazorSample.CustomEvents;

[EventHandler("oncustompaste", typeof(CustomPasteEventArgs), 
    enableStopPropagation: true, enablePreventDefault: true)]
public static class EventHandlers
{
}

public class CustomPasteEventArgs : EventArgs
{
    public DateTime EventTimestamp { get; set; }
    public string? PastedData { get; set; }
}

前述の JavaScript 初期化子のハンドラーを使用して、EventArgs サブクラスのデータを提供する JavaScript コードを追加します。 次の例では、テキストの貼り付けのみを処理しますが、任意の JavaScript API を使用して、ユーザーによる他の種類のデータ (画像など) の貼り付けを処理することもできます。

wwwroot/{PACKAGE ID/ASSEMBLY NAME}.lib.module.js:

export function afterStarted(blazor) {
  blazor.registerCustomEventType('custompaste', {
    browserEventName: 'paste',
    createEventArgs: event => {
      return {
        eventTimestamp: new Date(),
        pastedData: event.clipboardData.getData('text')
      };
    }
  });
}

前述の例では、ファイル名の {PACKAGE ID/ASSEMBLY NAME} プレースホルダーは、アプリのパッケージ ID またはアセンブリ名を表します。

注意

registerCustomEventType の呼び出しには、afterStarted によって提供される blazor パラメーター (b は小文字) を使用します。 Blazor オブジェクト (B は大文字) を使用しても登録は有効ですが、パラメーターを使用することをお勧めします。

上記のコードでは、ネイティブの paste イベントが発生したときに、次のことをブラウザーに指示します。

  • custompaste イベントを発生させる。
  • 次に示したカスタムロジックを使用して、イベント引数データを指定する。
    • eventTimestamp の場合は、新しい日付を作成します。
    • pastedData の場合は、クリップボード データをテキストとして取得します。 詳細については、「MDN Web Docs: ClipboardEvent.clipboardData」を参照してください。

イベント名の規則は、.NET と JavaScript で異なります。

  • .NET では、イベント名の先頭に "on" が付きます。
  • JavaScript では、イベント名にプレフィックスは付きません。

Razor コンポーネントでは、カスタム ハンドラーを要素にアタッチします。

Pages/CustomPasteArguments.razor:

@page "/custom-paste-arguments"
@using BlazorSample.CustomEvents

<label>
    Try pasting into the following text box:
    <input @oncustompaste="HandleCustomPaste" />
</label>

<p>
    @message
</p>

@code {
    private string? message;

    private void HandleCustomPaste(CustomPasteEventArgs eventArgs)
    {
        message = $"At {eventArgs.EventTimestamp.ToShortTimeString()}, " +
            $"you pasted: {eventArgs.PastedData}";
    }
}

ラムダ式

ラムダ式 は、デリゲート イベント ハンドラーとしてサポートされています。

Pages/EventHandlerExample4.razor:

@page "/event-handler-example-4"

<h1>@heading</h1>

<p>
    <button @onclick="@(e => heading = "New heading!!!")">
        Update heading
    </button>
</p>

@code {
    private string heading = "Initial heading";
}

要素のセットを反復処理するときなど、C# メソッド パラメーターを使用して追加の値に集中すると便利な場合がよくあります。 次の例では、3 つのボタンを作成します。それぞれを押すと、UpdateHeading が呼び出され、次のデータが渡されます。

  • e に対してイベント引数 (MouseEventArgs)。
  • buttonNumber に対してボタン番号。

Pages/EventHandlerExample5.razor:

@page "/event-handler-example-5"

<h1>@heading</h1>

@for (var i = 1; i < 4; i++)
{
    var buttonNumber = i;

    <p>
        <button @onclick="@(e => UpdateHeading(e, buttonNumber))">
            Button #@i
        </button>
    </p>
}

@code {
    private string heading = "Select a button to learn its position";

    private void UpdateHeading(MouseEventArgs e, int buttonNumber)
    {
        heading = $"Selected #{buttonNumber} at {e.ClientX}:{e.ClientY}";
    }
}

ループ内に多数のイベント委任を作成すると、レンダリングのパフォーマンスが低下する可能性があります。 詳しくは、「ASP.NET Core Blazor のパフォーマンスに関するベスト プラクティス」をご覧ください。

前の for ループの例の i など、ラムダ式内で直接ループ変数を使用することは避けてください。 そうしないと、すべてのラムダ式で同じ変数が使用され、すべてのラムダで同じ値が使用されることになります。 変数の値をローカル変数に取得してください。 前の例の場合:

  • ループ変数 ibuttonNumber に割り当てられます。
  • buttonNumber はラムダ式で使用されます。

または、foreach ループと Enumerable.Range を使います。このようにすると上記の問題は発生しません。

@foreach (var buttonNumber in Enumerable.Range(1,3))
{
    <p>
        <button @onclick="@(e => UpdateHeading(e, buttonNumber))">
            Button #@buttonNumber
        </button>
    </p>
}

EventCallback

入れ子になったコンポーネントがある一般的なシナリオでは、子コンポーネントのイベントが発生したときに親コンポーネントのメソッドを実行します。 子コンポーネントで発生する onclick イベントが、一般的なユース ケースです。 コンポーネント間にわたってイベントを公開するには、EventCallback を使用します。 親コンポーネントでは、コールバック メソッドを子コンポーネントの EventCallback に割り当てることができます。

次の Child は、ボタンの onclick ハンドラーがどのように、サンプルの ParentComponent から EventCallback デリゲートを受け取るように設定されているかを示しています。 EventCallbackMouseEventArgs によって型指定されます。これは、周辺機器の onclick イベントに適しています。

Shared/Child.razor:

<p>
    <button @onclick="OnClickCallback">
        Trigger a Parent component method
    </button>
</p>

@code {
    [Parameter]
    public string? Title { get; set; }

    [Parameter]
    public RenderFragment? ChildContent { get; set; }

    [Parameter]
    public EventCallback<MouseEventArgs> OnClickCallback { get; set; }
}

Parent コンポーネントでは、子の EventCallback<TValue> (OnClickCallback) を ShowMessage メソッドに設定しています。

Pages/Parent.razor:

@page "/parent"

<h1>Parent-child example</h1>

<Child Title="Panel Title from Parent" OnClickCallback="@ShowMessage">
    Content of the child component is supplied by the parent component.
</Child>

<p>@message</p>

@code {
    private string? message;

    private void ShowMessage(MouseEventArgs e)
    {
        message = $"Blaze a new trail with Blazor! ({e.ScreenX}:{e.ScreenY})";
    }
}

ChildComponent でボタンが選択されると:

  • Parent コンポーネントの ShowMessage メソッドが呼び出されます。 message が更新されて、Parent コンポーネントに表示されます。
  • コールバックのメソッド (ShowMessage) 内に、StateHasChanged の呼び出しは必要ありません。 StateHasChanged は、子イベントが子の中で実行されるイベント ハンドラーでコンポーネントのレンダリングをトリガーするのと同様に、Parent コンポーネントを再レンダリングするために自動的に呼び出されます。 詳しくは、「ASP.NET Core Razor コンポーネントのレンダリング」をご覧ください。

EventCallbackEventCallback<TValue> では非同期デリゲートを使用できます。 EventCallback は弱く型指定されており、InvokeAsync(Object) では任意の型の引数を渡すことができます。 EventCallback<TValue> は厳密に型指定されており、InvokeAsync(T) では TValue に代入可能な T 引数を渡す必要があります。

<ChildComponent 
    OnClickCallback="@(async () => { await Task.Yield(); messageText = "Blaze It!"; })" />

InvokeAsync を使用して EventCallback または EventCallback<TValue> を呼び出して、Task を待機します。

await OnClickCallback.InvokeAsync(arg);

イベント処理とバインド コンポーネントのパラメーターには、EventCallbackEventCallback<TValue> を使用します。

厳密に型指定された EventCallback<TValue>EventCallback よりも優先します。 EventCallback<TValue> からは、強化されたエラー フィードバックがコンポーネントのユーザーに提供されます。 他の UI イベント ハンドラーと同様に、このイベント パラメーターの指定は省略可能です。 コールバックに渡される値がない場合は、EventCallback を使用します。

既定のアクションを止める

イベントの既定のアクションを防止するには、@on{DOM EVENT}:preventDefault ディレクティブ属性を使用します。ここで、{DOM EVENT} プレースホルダーは、ドキュメント オブジェクト モデル (DOM) イベントです。

入力デバイスでキーが選択され、要素のフォーカスがテキスト ボックス上にあるときは、通常、ブラウザーによってテキスト ボックスにキーの文字が表示されます。 次の例では、@onkeydown:preventDefault ディレクティブ属性を指定することで、既定の動作が止められています。 <input> 要素にフォーカスがある場合、カウンターはキー シーケンス Shift++ が押されるとインクリメントします。 + 文字は、<input> 要素の値に割り当てられていません。 keydown の詳細については、「MDN Web Docs: Document: keydown イベント」を参照してください。

Pages/EventHandlerExample6.razor:

@page "/event-handler-example-6"

<p>
    <input value="@count" @onkeydown="KeyHandler" @onkeydown:preventDefault />
</p>

@code {
    private int count = 0;

    private void KeyHandler(KeyboardEventArgs e)
    {
        if (e.Key == "+")
        {
            count++;
        }
    }
}

値なしで @on{DOM EVENT}:preventDefault 属性を指定することは、@on{DOM EVENT}:preventDefault="true" と同じことになります。

式は、許可されている属性値でもあります。 次の例では、shouldPreventDefaulttrue または false のいずれかに設定される bool フィールドです。

<input @onkeydown:preventDefault="shouldPreventDefault" />

...

@code {
    private bool shouldPreventDefault = true;
}

イベント伝達を停止する

Blazor スクリプト内でイベント伝達を停止するには、@on{DOM EVENT}:stopPropagation ディレクティブ属性を使用します。 {DOM EVENT} プレースホルダーは ドキュメント オブジェクト モデル (DOM) イベントです

stopPropagation ディレクティブ属性の効果は Blazor スコープに限定され、HTML DOM まで拡大されることはありません。 イベントは、それに基づいて Blazor が動作する前に HTML DOM ルートに反映される必要があります。 HTML DOM イベントの伝達を防止するメカニズムについては、次の方法を検討してください。

次の例では、チェックボックスをオンにすると、2 番目の子 <div> からのクリック イベントが親の <div> に伝達されなくなります。 クリック イベントが伝達されると、通常、OnSelectParentDiv メソッドが起動されるので、2 番目の子 <div> を選択すると、チェックボックスがオンになっていない限り、親の <div> メッセージが表示されます。

Pages/EventHandlerExample7.razor:

@page "/event-handler-example-7"

<label>
    <input @bind="stopPropagation" type="checkbox" />
    Stop Propagation
</label>

<div class="m-1 p-1 border border-primary" @onclick="OnSelectParentDiv">
    <h3>Parent div</h3>

    <div class="m-1 p-1 border" @onclick="OnSelectChildDiv">
        Child div that doesn't stop propagation when selected.
    </div>

    <div class="m-1 p-1 border" @onclick="OnSelectChildDiv" 
            @onclick:stopPropagation="stopPropagation">
        Child div that stops propagation when selected.
    </div>
</div>

<p>
    @message
</p>

@code {
    private bool stopPropagation = false;
    private string? message; 

    private void OnSelectParentDiv() =>
        message = $"The parent div was selected. {DateTime.Now}";

    private void OnSelectChildDiv() =>
        message = $"A child div was selected. {DateTime.Now}";
}

要素にフォーカスを合わせる

コード内の要素にフォーカスを合わせるには、要素参照FocusAsync を呼び出します。 次の例では、ボタンを選択して <input> 要素にフォーカスを移動します。

Pages/EventHandlerExample8.razor:

@page "/event-handler-example-8"

<p>
    <input @ref="exampleInput" />
</p>

<button @onclick="ChangeFocus">
    Focus the Input Element
</button>

@code {
    private ElementReference exampleInput;

    private async Task ChangeFocus()
    {
        await exampleInput.FocusAsync();
    }
}

次の @on{DOM EVENT}="{DELEGATE}"Razor 構文を使用して、Razor コンポーネント マークアップでデリゲート イベント ハンドラーを指定します。

イベント処理の場合:

  • Task を返す非同期デリゲート イベント ハンドラーがサポートされています。
  • デリゲート イベント ハンドラーによって UI レンダリングが自動的にトリガーされるため、StateHasChanged を手動で呼び出す必要はありません。
  • 例外がログされます。

コード例を次に示します。

  • UI 内でボタンが選択されたときに UpdateHeading メソッドを呼び出します。
  • UI 内でチェックボックスが変更されたときに CheckChanged メソッドを呼び出します。

Pages/EventHandlerExample1.razor:

@page "/event-handler-example-1"

<h1>@currentHeading</h1>

<p>
    <label>
        New title
        <input @bind="newHeading" />
    </label>
    <button @onclick="UpdateHeading">
        Update heading
    </button>
</p>

<p>
    <label>
        <input type="checkbox" @onchange="CheckChanged" />
        @checkedMessage
    </label>
</p>

@code {
    private string currentHeading = "Initial heading";
    private string? newHeading;
    private string checkedMessage = "Not changed yet";

    private void UpdateHeading()
    {
        currentHeading = $"{newHeading}!!!";
    }

    private void CheckChanged()
    {
        checkedMessage = $"Last changed at {DateTime.Now}";
    }
}

UpdateHeading は、以下の例では次のようになります。

  • ボタンが選択されると、非同期に呼び出されます。
  • 2 秒間待機してから、見出しを更新します。

Pages/EventHandlerExample2.razor:

@page "/event-handler-example-2"

<h1>@currentHeading</h1>

<p>
    <label>
        New title
        <input @bind="newHeading" />
    </label>
    <button @onclick="UpdateHeading">
        Update heading
    </button>
</p>

@code {
    private string currentHeading = "Initial heading";
    private string? newHeading;

    private async Task UpdateHeading()
    {
        await Task.Delay(2000);

        currentHeading = $"{newHeading}!!!";
    }
}

イベント引数

組み込みのイベント引数

イベント引数の型をサポートするイベントの場合、イベント メソッド定義でイベント パラメーターを指定する必要があるのは、イベントの型がメソッドで使用されている場合のみです。 次の例では、ReportPointerLocation メソッドで MouseEventArgs が使用されています。これにより、ユーザーが UI 内でボタンを選択すると、マウスの座標を報告するメッセージ テキストが設定されます。

Pages/EventHandlerExample3.razor:

@page "/event-handler-example-3"

@for (var i = 0; i < 4; i++)
{
    <p>
        <button @onclick="ReportPointerLocation">
            Where's my mouse pointer for this button?
        </button>
    </p>
}

<p>@mousePointerMessage</p>

@code {
    private string? mousePointerMessage;

    private void ReportPointerLocation(MouseEventArgs e)
    {
        mousePointerMessage = $"Mouse coordinates: {e.ScreenX}:{e.ScreenY}";
    }
}

サポートされている EventArgs を次の表に示します。

event クラス ドキュメント オブジェクト モデル (DOM) イベントと注記
クリップボードのトピック ClipboardEventArgs oncut, oncopy, onpaste
ドラッグ DragEventArgs ondrag, ondragstart, ondragenter, ondragleave, ondragover, ondrop, ondragend

DataTransfer および DataTransferItem では、ドラッグされた項目データを保持します。

HTML ドラッグ アンド ドロップ API と共に JS 相互運用を使用し、Blazor アプリにドラッグ アンド ドロップを実装します。
エラー ErrorEventArgs onerror
event EventArgs 全般
onactivate, onbeforeactivate, onbeforedeactivate, ondeactivate, onfullscreenchange, onfullscreenerror, onloadeddata, onloadedmetadata, onpointerlockchange, onpointerlockerror, onreadystatechange, onscroll

クリップボード
onbeforecut, onbeforecopy, onbeforepaste

入力
oninvalid, onreset, onselect, onselectionchange, onselectstart, onsubmit

メディア
oncanplay, oncanplaythrough, oncuechange, ondurationchange, onemptied, onended, onpause, onplay, onplaying, onratechange, onseeked, onseeking, onstalled, onstop, onsuspend, ontimeupdate, ontoggle, onvolumechange, onwaiting

EventHandlers は、イベント名とイベント引数の型の間のマッピングを構成する属性を保持します。
フォーカス FocusEventArgs onfocus, onblur, onfocusin, onfocusout

relatedTarget のサポートは含まれません。
入力 ChangeEventArgs onchange, oninput
キーボード KeyboardEventArgs onkeydown, onkeypress, onkeyup
マウス MouseEventArgs onclick, oncontextmenu, ondblclick, onmousedown, onmouseup, onmouseover, onmousemove, onmouseout
マウス ポインター PointerEventArgs onpointerdown, onpointerup, onpointercancel, onpointermove, onpointerover, onpointerout, onpointerenter, onpointerleave, ongotpointercapture, onlostpointercapture
マウス ホイール WheelEventArgs onwheel, onmousewheel
進行状況 ProgressEventArgs onabort, onload, onloadend, onloadstart, onprogress, ontimeout
タッチ TouchEventArgs ontouchstart, ontouchend, ontouchmove, ontouchenter, ontouchleave, ontouchcancel

TouchPoint は、タッチを検知するデバイス上の単一接触点を表します。

詳細については、ASP.NET Core 参照ソース内の EventArgs クラス (dotnet/aspnetcore main ブランチ) を参照してください。

注意

通常、.NET 参照ソースへのドキュメント リンクを使用すると、リポジトリの既定のブランチが読み込まれます。このブランチは、.NET の次回リリースに向けて行われている現在の開発を表します。 特定のリリースのタグを選択するには、[Switch branches or tags](ブランチまたはタグの切り替え) ドロップダウン リストを使います。 詳細については、「ASP.NET Core ソース コードのバージョン タグを選択する方法」 (dotnet/AspNetCore.Docs #26205) を参照してください。

カスタム イベント引数

Blazor ではカスタム イベント引数がサポートされています。このため、カスタム イベントを使用して任意のデータを .NET イベント ハンドラーに渡すことができます。

全般構成

カスタム イベント引数を使用したカスタム イベントは、一般に次の手順によって有効にされます。

  1. JavaScript では、ソース イベントからカスタム イベント引数オブジェクトをビルドするための関数を定義します。

    function eventArgsCreator(event) { 
      return {
        customProperty1: 'any value for property 1',
        customProperty2: event.srcElement.value
      };
    }
    
  2. カスタム イベントを、前述の JavaScript 初期化子のハンドラーに登録します。

    wwwroot/{PACKAGE ID/ASSEMBLY NAME}.lib.module.js:

    export function afterStarted(blazor) {
      blazor.registerCustomEventType('customevent', {
        createEventArgs: eventArgsCreator
      });
    }
    

    前述の例では、ファイル名の {PACKAGE ID/ASSEMBLY NAME} プレースホルダーは、アプリのパッケージ ID またはアセンブリ名を表します。

    Note

    registerCustomEventType の呼び出しは、1 つのイベントにつき 1 回だけスクリプト内で実行されます。

    registerCustomEventType の呼び出しには、afterStarted によって提供される blazor パラメーター (b は小文字) を使用します。 Blazor オブジェクト (B は大文字) を使用しても登録は有効ですが、パラメーターを使用することをお勧めします。

  3. イベント引数のクラスは次のように定義します。

    namespace BlazorSample.CustomEvents;
    
    public class CustomEventArgs : EventArgs
    {
        public string? CustomProperty1 {get; set;}
        public string? CustomProperty2 {get; set;}
    }
    
  4. カスタム イベントに関する EventHandlerAttribute 属性注釈を追加することによって、イベント引数を使用したカスタム イベントを接続します。

    • コンパイラで [EventHandler] クラスを検出できるようにするには、C# クラス ファイル (.cs) に配置し、通常の最上位クラスにする必要があります。
    • クラスに public とマークを付けます。
    • このクラスにメンバーは必要ありません。
    • このクラスは、Razor コンパイラで検出できるように "EventHandlers" という名前にする "必要があります"。
    • クラスをアプリに固有の名前空間の下に配置します。
    • イベントが使用される Razor コンポーネント (.razor) に名前空間をインポートします。
    using Microsoft.AspNetCore.Components;
    
    namespace BlazorSample.CustomEvents;
    
    [EventHandler("oncustomevent", typeof(CustomEventArgs), enableStopPropagation: true, enablePreventDefault: true)]
    public static class EventHandlers
    {
    }
    
  5. 1 つまたは複数の HTML 要素に対してイベント ハンドラーを登録します。 デリゲート ハンドラー メソッドで JavaScript から渡されたデータにアクセスします。

    @using namespace BlazorSample.CustomEvents
    
    <button @oncustomevent="HandleCustomEvent">Handle</button>
    
    @code
    {
        private void HandleCustomEvent(CustomEventArgs eventArgs)
        {
            // eventArgs.CustomProperty1
            // eventArgs.CustomProperty2
        }
    }
    

@oncustomevent 属性が IntelliSense によって認識されない場合は、コンポーネントまたは _Imports.razor ファイルに、EventHandler クラスを含む名前空間の @using ステートメントが必ず含まれるようにしてください。

DOM 上でカスタム イベントが発生するたびに、JavaScript から渡されたデータを使用してイベント ハンドラーが呼び出されます。

カスタム イベントを発生させようとしている場合は、bubbles を有効にするために、その値を true に設定する必要があります。 それを行わない場合は、イベントが発生しても、処理用の Blazor ハンドラーが C# カスタム EventHandlerAttribute メソッドに到達することはありません。 詳細については、「MDN Web Docs: イベントのバブリング」を参照してください。

カスタム クリップボードの貼り付けイベントの例

次の例では、貼り付けの時刻とユーザーが貼り付けたテキストを含む、カスタム クリップボードの貼り付けイベントを受け取ります。

イベントのカスタム名 (oncustompaste) と、このイベントのイベント引数を保持する .NET クラス (CustomPasteEventArgs) を宣言します。

CustomEvents.cs:

using Microsoft.AspNetCore.Components;

namespace BlazorSample.CustomEvents;

[EventHandler("oncustompaste", typeof(CustomPasteEventArgs), 
    enableStopPropagation: true, enablePreventDefault: true)]
public static class EventHandlers
{
}

public class CustomPasteEventArgs : EventArgs
{
    public DateTime EventTimestamp { get; set; }
    public string? PastedData { get; set; }
}

前述の JavaScript 初期化子のハンドラーを使用して、EventArgs サブクラスのデータを提供する JavaScript コードを追加します。 次の例では、テキストの貼り付けのみを処理しますが、任意の JavaScript API を使用して、ユーザーによる他の種類のデータ (画像など) の貼り付けを処理することもできます。

wwwroot/{PACKAGE ID/ASSEMBLY NAME}.lib.module.js:

export function afterStarted(blazor) {
  blazor.registerCustomEventType('custompaste', {
    browserEventName: 'paste',
    createEventArgs: event => {
      return {
        eventTimestamp: new Date(),
        pastedData: event.clipboardData.getData('text')
      };
    }
  });
}

前述の例では、ファイル名の {PACKAGE ID/ASSEMBLY NAME} プレースホルダーは、アプリのパッケージ ID またはアセンブリ名を表します。

注意

registerCustomEventType の呼び出しには、afterStarted によって提供される blazor パラメーター (b は小文字) を使用します。 Blazor オブジェクト (B は大文字) を使用しても登録は有効ですが、パラメーターを使用することをお勧めします。

上記のコードでは、ネイティブの paste イベントが発生したときに、次のことをブラウザーに指示します。

  • custompaste イベントを発生させる。
  • 次に示したカスタムロジックを使用して、イベント引数データを指定する。
    • eventTimestamp の場合は、新しい日付を作成します。
    • pastedData の場合は、クリップボード データをテキストとして取得します。 詳細については、「MDN Web Docs: ClipboardEvent.clipboardData」を参照してください。

イベント名の規則は、.NET と JavaScript で異なります。

  • .NET では、イベント名の先頭に "on" が付きます。
  • JavaScript では、イベント名にプレフィックスは付きません。

Razor コンポーネントでは、カスタム ハンドラーを要素にアタッチします。

Pages/CustomPasteArguments.razor:

@page "/custom-paste-arguments"
@using BlazorSample.CustomEvents

<label>
    Try pasting into the following text box:
    <input @oncustompaste="HandleCustomPaste" />
</label>

<p>
    @message
</p>

@code {
    private string? message;

    private void HandleCustomPaste(CustomPasteEventArgs eventArgs)
    {
        message = $"At {eventArgs.EventTimestamp.ToShortTimeString()}, " +
            $"you pasted: {eventArgs.PastedData}";
    }
}

ラムダ式

ラムダ式 は、デリゲート イベント ハンドラーとしてサポートされています。

Pages/EventHandlerExample4.razor:

@page "/event-handler-example-4"

<h1>@heading</h1>

<p>
    <button @onclick="@(e => heading = "New heading!!!")">
        Update heading
    </button>
</p>

@code {
    private string heading = "Initial heading";
}

要素のセットを反復処理するときなど、C# メソッド パラメーターを使用して追加の値に集中すると便利な場合がよくあります。 次の例では、3 つのボタンを作成します。それぞれを押すと、UpdateHeading が呼び出され、次のデータが渡されます。

  • e に対してイベント引数 (MouseEventArgs)。
  • buttonNumber に対してボタン番号。

Pages/EventHandlerExample5.razor:

@page "/event-handler-example-5"

<h1>@heading</h1>

@for (var i = 1; i < 4; i++)
{
    var buttonNumber = i;

    <p>
        <button @onclick="@(e => UpdateHeading(e, buttonNumber))">
            Button #@i
        </button>
    </p>
}

@code {
    private string heading = "Select a button to learn its position";

    private void UpdateHeading(MouseEventArgs e, int buttonNumber)
    {
        heading = $"Selected #{buttonNumber} at {e.ClientX}:{e.ClientY}";
    }
}

ループ内に多数のイベント委任を作成すると、レンダリングのパフォーマンスが低下する可能性があります。 詳しくは、「ASP.NET Core Blazor のパフォーマンスに関するベスト プラクティス」をご覧ください。

前の for ループの例の i など、ラムダ式内で直接ループ変数を使用することは避けてください。 そうしないと、すべてのラムダ式で同じ変数が使用され、すべてのラムダで同じ値が使用されることになります。 変数の値をローカル変数に取得してください。 前の例の場合:

  • ループ変数 ibuttonNumber に割り当てられます。
  • buttonNumber はラムダ式で使用されます。

または、foreach ループと Enumerable.Range を使います。このようにすると上記の問題は発生しません。

@foreach (var buttonNumber in Enumerable.Range(1,3))
{
    <p>
        <button @onclick="@(e => UpdateHeading(e, buttonNumber))">
            Button #@buttonNumber
        </button>
    </p>
}

EventCallback

入れ子になったコンポーネントがある一般的なシナリオでは、子コンポーネントのイベントが発生したときに親コンポーネントのメソッドを実行します。 子コンポーネントで発生する onclick イベントが、一般的なユース ケースです。 コンポーネント間にわたってイベントを公開するには、EventCallback を使用します。 親コンポーネントでは、コールバック メソッドを子コンポーネントの EventCallback に割り当てることができます。

次の Child は、ボタンの onclick ハンドラーがどのように、サンプルの ParentComponent から EventCallback デリゲートを受け取るように設定されているかを示しています。 EventCallbackMouseEventArgs によって型指定されます。これは、周辺機器の onclick イベントに適しています。

Shared/Child.razor:

<p>
    <button @onclick="OnClickCallback">
        Trigger a Parent component method
    </button>
</p>

@code {
    [Parameter]
    public string? Title { get; set; }

    [Parameter]
    public RenderFragment? ChildContent { get; set; }

    [Parameter]
    public EventCallback<MouseEventArgs> OnClickCallback { get; set; }
}

Parent コンポーネントでは、子の EventCallback<TValue> (OnClickCallback) を ShowMessage メソッドに設定しています。

Pages/Parent.razor:

@page "/parent"

<h1>Parent-child example</h1>

<Child Title="Panel Title from Parent" OnClickCallback="@ShowMessage">
    Content of the child component is supplied by the parent component.
</Child>

<p>@message</p>

@code {
    private string? message;

    private void ShowMessage(MouseEventArgs e)
    {
        message = $"Blaze a new trail with Blazor! ({e.ScreenX}:{e.ScreenY})";
    }
}

ChildComponent でボタンが選択されると:

  • Parent コンポーネントの ShowMessage メソッドが呼び出されます。 message が更新されて、Parent コンポーネントに表示されます。
  • コールバックのメソッド (ShowMessage) 内に、StateHasChanged の呼び出しは必要ありません。 StateHasChanged は、子イベントが子の中で実行されるイベント ハンドラーでコンポーネントのレンダリングをトリガーするのと同様に、Parent コンポーネントを再レンダリングするために自動的に呼び出されます。 詳しくは、「ASP.NET Core Razor コンポーネントのレンダリング」をご覧ください。

EventCallbackEventCallback<TValue> では非同期デリゲートを使用できます。 EventCallback は弱く型指定されており、InvokeAsync(Object) では任意の型の引数を渡すことができます。 EventCallback<TValue> は厳密に型指定されており、InvokeAsync(T) では TValue に代入可能な T 引数を渡す必要があります。

<ChildComponent 
    OnClickCallback="@(async () => { await Task.Yield(); messageText = "Blaze It!"; })" />

InvokeAsync を使用して EventCallback または EventCallback<TValue> を呼び出して、Task を待機します。

await OnClickCallback.InvokeAsync(arg);

イベント処理とバインド コンポーネントのパラメーターには、EventCallbackEventCallback<TValue> を使用します。

厳密に型指定された EventCallback<TValue>EventCallback よりも優先します。 EventCallback<TValue> からは、強化されたエラー フィードバックがコンポーネントのユーザーに提供されます。 他の UI イベント ハンドラーと同様に、このイベント パラメーターの指定は省略可能です。 コールバックに渡される値がない場合は、EventCallback を使用します。

既定のアクションを止める

イベントの既定のアクションを防止するには、@on{DOM EVENT}:preventDefault ディレクティブ属性を使用します。ここで、{DOM EVENT} プレースホルダーは、ドキュメント オブジェクト モデル (DOM) イベントです。

入力デバイスでキーが選択され、要素のフォーカスがテキスト ボックス上にあるときは、通常、ブラウザーによってテキスト ボックスにキーの文字が表示されます。 次の例では、@onkeydown:preventDefault ディレクティブ属性を指定することで、既定の動作が止められています。 <input> 要素にフォーカスがある場合、カウンターはキー シーケンス Shift++ が押されるとインクリメントします。 + 文字は、<input> 要素の値に割り当てられていません。 keydown の詳細については、「MDN Web Docs: Document: keydown イベント」を参照してください。

Pages/EventHandlerExample6.razor:

@page "/event-handler-example-6"

<p>
    <input value="@count" @onkeydown="KeyHandler" @onkeydown:preventDefault />
</p>

@code {
    private int count = 0;

    private void KeyHandler(KeyboardEventArgs e)
    {
        if (e.Key == "+")
        {
            count++;
        }
    }
}

値なしで @on{DOM EVENT}:preventDefault 属性を指定することは、@on{DOM EVENT}:preventDefault="true" と同じことになります。

式は、許可されている属性値でもあります。 次の例では、shouldPreventDefaulttrue または false のいずれかに設定される bool フィールドです。

<input @onkeydown:preventDefault="shouldPreventDefault" />

...

@code {
    private bool shouldPreventDefault = true;
}

イベント伝達を停止する

Blazor スクリプト内でイベント伝達を停止するには、@on{DOM EVENT}:stopPropagation ディレクティブ属性を使用します。 {DOM EVENT} プレースホルダーは ドキュメント オブジェクト モデル (DOM) イベントです

stopPropagation ディレクティブ属性の効果は Blazor スコープに限定され、HTML DOM まで拡大されることはありません。 イベントは、それに基づいて Blazor が動作する前に HTML DOM ルートに反映される必要があります。 HTML DOM イベントの伝達を防止するメカニズムについては、次の方法を検討してください。

次の例では、チェックボックスをオンにすると、2 番目の子 <div> からのクリック イベントが親の <div> に伝達されなくなります。 クリック イベントが伝達されると、通常、OnSelectParentDiv メソッドが起動されるので、2 番目の子 <div> を選択すると、チェックボックスがオンになっていない限り、親の <div> メッセージが表示されます。

Pages/EventHandlerExample7.razor:

@page "/event-handler-example-7"

<label>
    <input @bind="stopPropagation" type="checkbox" />
    Stop Propagation
</label>

<div class="m-1 p-1 border border-primary" @onclick="OnSelectParentDiv">
    <h3>Parent div</h3>

    <div class="m-1 p-1 border" @onclick="OnSelectChildDiv">
        Child div that doesn't stop propagation when selected.
    </div>

    <div class="m-1 p-1 border" @onclick="OnSelectChildDiv" 
            @onclick:stopPropagation="stopPropagation">
        Child div that stops propagation when selected.
    </div>
</div>

<p>
    @message
</p>

@code {
    private bool stopPropagation = false;
    private string? message; 

    private void OnSelectParentDiv() =>
        message = $"The parent div was selected. {DateTime.Now}";

    private void OnSelectChildDiv() =>
        message = $"A child div was selected. {DateTime.Now}";
}

要素にフォーカスを合わせる

コード内の要素にフォーカスを合わせるには、要素参照FocusAsync を呼び出します。 次の例では、ボタンを選択して <input> 要素にフォーカスを移動します。

Pages/EventHandlerExample8.razor:

@page "/event-handler-example-8"

<p>
    <input @ref="exampleInput" />
</p>

<button @onclick="ChangeFocus">
    Focus the Input Element
</button>

@code {
    private ElementReference exampleInput;

    private async Task ChangeFocus()
    {
        await exampleInput.FocusAsync();
    }
}

次の @on{DOM EVENT}="{DELEGATE}"Razor 構文を使用して、Razor コンポーネント マークアップでデリゲート イベント ハンドラーを指定します。

イベント処理の場合:

  • Task を返す非同期デリゲート イベント ハンドラーがサポートされています。
  • デリゲート イベント ハンドラーによって UI レンダリングが自動的にトリガーされるため、StateHasChanged を手動で呼び出す必要はありません。
  • 例外がログされます。

コード例を次に示します。

  • UI 内でボタンが選択されたときに UpdateHeading メソッドを呼び出します。
  • UI 内でチェックボックスが変更されたときに CheckChanged メソッドを呼び出します。

Pages/EventHandlerExample1.razor:

@page "/event-handler-example-1"

<h1>@currentHeading</h1>

<p>
    <label>
        New title
        <input @bind="newHeading" />
    </label>
    <button @onclick="UpdateHeading">
        Update heading
    </button>
</p>

<p>
    <label>
        <input type="checkbox" @onchange="CheckChanged" />
        @checkedMessage
    </label>
</p>

@code {
    private string currentHeading = "Initial heading";
    private string newHeading;
    private string checkedMessage = "Not changed yet";

    private void UpdateHeading()
    {
        currentHeading = $"{newHeading}!!!";
    }

    private void CheckChanged()
    {
        checkedMessage = $"Last changed at {DateTime.Now}";
    }
}

UpdateHeading は、以下の例では次のようになります。

  • ボタンが選択されると、非同期に呼び出されます。
  • 2 秒間待機してから、見出しを更新します。

Pages/EventHandlerExample2.razor:

@page "/event-handler-example-2"

<h1>@currentHeading</h1>

<p>
    <label>
        New title
        <input @bind="newHeading" />
    </label>
    <button @onclick="UpdateHeading">
        Update heading
    </button>
</p>

@code {
    private string currentHeading = "Initial heading";
    private string newHeading;

    private async Task UpdateHeading()
    {
        await Task.Delay(2000);

        currentHeading = $"{newHeading}!!!";
    }
}

イベント引数

イベント引数の型をサポートするイベントの場合、イベント メソッド定義でイベント パラメーターを指定する必要があるのは、イベントの型がメソッドで使用されている場合のみです。 次の例では、ReportPointerLocation メソッドで MouseEventArgs が使用されています。これにより、ユーザーが UI 内でボタンを選択すると、マウスの座標を報告するメッセージ テキストが設定されます。

Pages/EventHandlerExample3.razor:

@page "/event-handler-example-3"

@for (var i = 0; i < 4; i++)
{
    <p>
        <button @onclick="ReportPointerLocation">
            Where's my mouse pointer for this button?
        </button>
    </p>
}

<p>@mousePointerMessage</p>

@code {
    private string mousePointerMessage;

    private void ReportPointerLocation(MouseEventArgs e)
    {
        mousePointerMessage = $"Mouse coordinates: {e.ScreenX}:{e.ScreenY}";
    }
}

サポートされている EventArgs を次の表に示します。

event クラス ドキュメント オブジェクト モデル (DOM) イベントと注記
クリップボードのトピック ClipboardEventArgs oncut, oncopy, onpaste
ドラッグ DragEventArgs ondrag, ondragstart, ondragenter, ondragleave, ondragover, ondrop, ondragend

DataTransfer および DataTransferItem では、ドラッグされた項目データを保持します。

HTML ドラッグ アンド ドロップ API と共に JS 相互運用を使用し、Blazor アプリにドラッグ アンド ドロップを実装します。
エラー ErrorEventArgs onerror
event EventArgs 全般
onactivate, onbeforeactivate, onbeforedeactivate, ondeactivate, onfullscreenchange, onfullscreenerror, onloadeddata, onloadedmetadata, onpointerlockchange, onpointerlockerror, onreadystatechange, onscroll

クリップボード
onbeforecut, onbeforecopy, onbeforepaste

入力
oninvalid, onreset, onselect, onselectionchange, onselectstart, onsubmit

メディア
oncanplay, oncanplaythrough, oncuechange, ondurationchange, onemptied, onended, onpause, onplay, onplaying, onratechange, onseeked, onseeking, onstalled, onstop, onsuspend, ontimeupdate, ontoggle, onvolumechange, onwaiting

EventHandlers は、イベント名とイベント引数の型の間のマッピングを構成する属性を保持します。
フォーカス FocusEventArgs onfocus, onblur, onfocusin, onfocusout

relatedTarget のサポートは含まれません。
入力 ChangeEventArgs onchange, oninput
キーボード KeyboardEventArgs onkeydown, onkeypress, onkeyup
マウス MouseEventArgs onclick, oncontextmenu, ondblclick, onmousedown, onmouseup, onmouseover, onmousemove, onmouseout
マウス ポインター PointerEventArgs onpointerdown, onpointerup, onpointercancel, onpointermove, onpointerover, onpointerout, onpointerenter, onpointerleave, ongotpointercapture, onlostpointercapture
マウス ホイール WheelEventArgs onwheel, onmousewheel
進行状況 ProgressEventArgs onabort, onload, onloadend, onloadstart, onprogress, ontimeout
タッチ TouchEventArgs ontouchstart, ontouchend, ontouchmove, ontouchenter, ontouchleave, ontouchcancel

TouchPoint は、タッチを検知するデバイス上の単一接触点を表します。

詳細については、ASP.NET Core 参照ソース内の EventArgs クラス (dotnet/aspnetcore main ブランチ) を参照してください

注意

通常、.NET 参照ソースへのドキュメント リンクを使用すると、リポジトリの既定のブランチが読み込まれます。このブランチは、.NET の次回リリースに向けて行われている現在の開発を表します。 特定のリリースのタグを選択するには、[Switch branches or tags](ブランチまたはタグの切り替え) ドロップダウン リストを使います。 詳細については、「ASP.NET Core ソース コードのバージョン タグを選択する方法」 (dotnet/AspNetCore.Docs #26205) を参照してください。

ラムダ式

ラムダ式 は、デリゲート イベント ハンドラーとしてサポートされています。

Pages/EventHandlerExample4.razor:

@page "/event-handler-example-4"

<h1>@heading</h1>

<p>
    <button @onclick="@(e => heading = "New heading!!!")">
        Update heading
    </button>
</p>

@code {
    private string heading = "Initial heading";
}

要素のセットを反復処理するときなど、C# メソッド パラメーターを使用して追加の値に集中すると便利な場合がよくあります。 次の例では、3 つのボタンを作成します。それぞれを押すと、UpdateHeading が呼び出され、次のデータが渡されます。

  • e に対してイベント引数 (MouseEventArgs)。
  • buttonNumber に対してボタン番号。

Pages/EventHandlerExample5.razor:

@page "/event-handler-example-5"

<h1>@heading</h1>

@for (var i = 1; i < 4; i++)
{
    var buttonNumber = i;

    <p>
        <button @onclick="@(e => UpdateHeading(e, buttonNumber))">
            Button #@i
        </button>
    </p>
}

@code {
    private string heading = "Select a button to learn its position";

    private void UpdateHeading(MouseEventArgs e, int buttonNumber)
    {
        heading = $"Selected #{buttonNumber} at {e.ClientX}:{e.ClientY}";
    }
}

ループ内に多数のイベント委任を作成すると、レンダリングのパフォーマンスが低下する可能性があります。 詳しくは、「ASP.NET Core Blazor のパフォーマンスに関するベスト プラクティス」をご覧ください。

前の for ループの例の i など、ラムダ式内で直接ループ変数を使用することは避けてください。 そうしないと、すべてのラムダ式で同じ変数が使用され、すべてのラムダで同じ値が使用されることになります。 変数の値をローカル変数に取得してください。 前の例の場合:

  • ループ変数 ibuttonNumber に割り当てられます。
  • buttonNumber はラムダ式で使用されます。

または、foreach ループと Enumerable.Range を使います。このようにすると上記の問題は発生しません。

@foreach (var buttonNumber in Enumerable.Range(1,3))
{
    <p>
        <button @onclick="@(e => UpdateHeading(e, buttonNumber))">
            Button #@buttonNumber
        </button>
    </p>
}

EventCallback

入れ子になったコンポーネントがある一般的なシナリオでは、子コンポーネントのイベントが発生したときに親コンポーネントのメソッドを実行します。 子コンポーネントで発生する onclick イベントが、一般的なユース ケースです。 コンポーネント間にわたってイベントを公開するには、EventCallback を使用します。 親コンポーネントでは、コールバック メソッドを子コンポーネントの EventCallback に割り当てることができます。

次の Child は、ボタンの onclick ハンドラーがどのように、サンプルの ParentComponent から EventCallback デリゲートを受け取るように設定されているかを示しています。 EventCallbackMouseEventArgs によって型指定されます。これは、周辺機器の onclick イベントに適しています。

Shared/Child.razor:

<p>
    <button @onclick="OnClickCallback">
        Trigger a Parent component method
    </button>
</p>

@code {
    [Parameter]
    public string Title { get; set; }

    [Parameter]
    public RenderFragment ChildContent { get; set; }

    [Parameter]
    public EventCallback<MouseEventArgs> OnClickCallback { get; set; }
}

Parent コンポーネントでは、子の EventCallback<TValue> (OnClickCallback) を ShowMessage メソッドに設定しています。

Pages/Parent.razor:

@page "/parent"

<h1>Parent-child example</h1>

<Child Title="Panel Title from Parent" OnClickCallback="@ShowMessage">
    Content of the child component is supplied by the parent component.
</Child>

<p>@message</p>

@code {
    private string message;

    private void ShowMessage(MouseEventArgs e)
    {
        message = $"Blaze a new trail with Blazor! ({e.ScreenX}:{e.ScreenY})";
    }
}

ChildComponent でボタンが選択されると:

  • Parent コンポーネントの ShowMessage メソッドが呼び出されます。 message が更新されて、Parent コンポーネントに表示されます。
  • コールバックのメソッド (ShowMessage) 内に、StateHasChanged の呼び出しは必要ありません。 StateHasChanged は、子イベントが子の中で実行されるイベント ハンドラーでコンポーネントのレンダリングをトリガーするのと同様に、Parent コンポーネントを再レンダリングするために自動的に呼び出されます。 詳しくは、「ASP.NET Core Razor コンポーネントのレンダリング」をご覧ください。

EventCallbackEventCallback<TValue> では非同期デリゲートを使用できます。 EventCallback は弱く型指定されており、InvokeAsync(Object) では任意の型の引数を渡すことができます。 EventCallback<TValue> は厳密に型指定されており、InvokeAsync(T) では TValue に代入可能な T 引数を渡す必要があります。

<ChildComponent 
    OnClickCallback="@(async () => { await Task.Yield(); messageText = "Blaze It!"; })" />

InvokeAsync を使用して EventCallback または EventCallback<TValue> を呼び出して、Task を待機します。

await OnClickCallback.InvokeAsync(arg);

イベント処理とバインド コンポーネントのパラメーターには、EventCallbackEventCallback<TValue> を使用します。

厳密に型指定された EventCallback<TValue>EventCallback よりも優先します。 EventCallback<TValue> からは、強化されたエラー フィードバックがコンポーネントのユーザーに提供されます。 他の UI イベント ハンドラーと同様に、このイベント パラメーターの指定は省略可能です。 コールバックに渡される値がない場合は、EventCallback を使用します。

既定のアクションを止める

イベントの既定のアクションを防止するには、@on{DOM EVENT}:preventDefault ディレクティブ属性を使用します。ここで、{DOM EVENT} プレースホルダーは、ドキュメント オブジェクト モデル (DOM) イベントです。

入力デバイスでキーが選択され、要素のフォーカスがテキスト ボックス上にあるときは、通常、ブラウザーによってテキスト ボックスにキーの文字が表示されます。 次の例では、@onkeydown:preventDefault ディレクティブ属性を指定することで、既定の動作が止められています。 <input> 要素にフォーカスがある場合、カウンターはキー シーケンス Shift++ が押されるとインクリメントします。 + 文字は、<input> 要素の値に割り当てられていません。 keydown の詳細については、「MDN Web Docs: Document: keydown イベント」を参照してください。

Pages/EventHandlerExample6.razor:

@page "/event-handler-example-6"

<p>
    <input value="@count" @onkeydown="KeyHandler" @onkeydown:preventDefault />
</p>

@code {
    private int count = 0;

    private void KeyHandler(KeyboardEventArgs e)
    {
        if (e.Key == "+")
        {
            count++;
        }
    }
}

値なしで @on{DOM EVENT}:preventDefault 属性を指定することは、@on{DOM EVENT}:preventDefault="true" と同じことになります。

式は、許可されている属性値でもあります。 次の例では、shouldPreventDefaulttrue または false のいずれかに設定される bool フィールドです。

<input @onkeydown:preventDefault="shouldPreventDefault" />

...

@code {
    private bool shouldPreventDefault = true;
}

イベント伝達を停止する

Blazor スクリプト内でイベント伝達を停止するには、@on{DOM EVENT}:stopPropagation ディレクティブ属性を使用します。 {DOM EVENT} プレースホルダーは ドキュメント オブジェクト モデル (DOM) イベントです

stopPropagation ディレクティブ属性の効果は Blazor スコープに限定され、HTML DOM まで拡大されることはありません。 イベントは、それに基づいて Blazor が動作する前に HTML DOM ルートに反映される必要があります。 HTML DOM イベントの伝達を防止するメカニズムについては、次の方法を検討してください。

次の例では、チェックボックスをオンにすると、2 番目の子 <div> からのクリック イベントが親の <div> に伝達されなくなります。 クリック イベントが伝達されると、通常、OnSelectParentDiv メソッドが起動されるので、2 番目の子 <div> を選択すると、チェックボックスがオンになっていない限り、親の <div> メッセージが表示されます。

Pages/EventHandlerExample7.razor:

@page "/event-handler-example-7"

<label>
    <input @bind="stopPropagation" type="checkbox" />
    Stop Propagation
</label>

<div class="m-1 p-1 border border-primary" @onclick="OnSelectParentDiv">
    <h3>Parent div</h3>

    <div class="m-1 p-1 border" @onclick="OnSelectChildDiv">
        Child div that doesn't stop propagation when selected.
    </div>

    <div class="m-1 p-1 border" @onclick="OnSelectChildDiv" 
            @onclick:stopPropagation="stopPropagation">
        Child div that stops propagation when selected.
    </div>
</div>

<p>
    @message
</p>

@code {
    private bool stopPropagation = false;
    private string message; 

    private void OnSelectParentDiv() =>
        message = $"The parent div was selected. {DateTime.Now}";

    private void OnSelectChildDiv() =>
        message = $"A child div was selected. {DateTime.Now}";
}

要素にフォーカスを合わせる

コード内の要素にフォーカスを合わせるには、要素参照FocusAsync を呼び出します。 次の例では、ボタンを選択して <input> 要素にフォーカスを移動します。

Pages/EventHandlerExample8.razor:

@page "/event-handler-example-8"

<p>
    <input @ref="exampleInput" />
</p>

<button @onclick="ChangeFocus">
    Focus the Input Element
</button>

@code {
    private ElementReference exampleInput;

    private async Task ChangeFocus()
    {
        await exampleInput.FocusAsync();
    }
}

次の @on{DOM EVENT}="{DELEGATE}"Razor 構文を使用して、Razor コンポーネント マークアップでデリゲート イベント ハンドラーを指定します。

イベント処理の場合:

  • Task を返す非同期デリゲート イベント ハンドラーがサポートされています。
  • デリゲート イベント ハンドラーによって UI レンダリングが自動的にトリガーされるため、StateHasChanged を手動で呼び出す必要はありません。
  • 例外がログされます。

コード例を次に示します。

  • UI 内でボタンが選択されたときに UpdateHeading メソッドを呼び出します。
  • UI 内でチェックボックスが変更されたときに CheckChanged メソッドを呼び出します。

Pages/EventHandlerExample1.razor:

@page "/event-handler-example-1"

<h1>@currentHeading</h1>

<p>
    <label>
        New title
        <input @bind="newHeading" />
    </label>
    <button @onclick="UpdateHeading">
        Update heading
    </button>
</p>

<p>
    <label>
        <input type="checkbox" @onchange="CheckChanged" />
        @checkedMessage
    </label>
</p>

@code {
    private string currentHeading = "Initial heading";
    private string newHeading;
    private string checkedMessage = "Not changed yet";

    private void UpdateHeading()
    {
        currentHeading = $"{newHeading}!!!";
    }

    private void CheckChanged()
    {
        checkedMessage = $"Last changed at {DateTime.Now}";
    }
}

UpdateHeading は、以下の例では次のようになります。

  • ボタンが選択されると、非同期に呼び出されます。
  • 2 秒間待機してから、見出しを更新します。

Pages/EventHandlerExample2.razor:

@page "/event-handler-example-2"

<h1>@currentHeading</h1>

<p>
    <label>
        New title
        <input @bind="newHeading" />
    </label>
    <button @onclick="UpdateHeading">
        Update heading
    </button>
</p>

@code {
    private string currentHeading = "Initial heading";
    private string newHeading;

    private async Task UpdateHeading()
    {
        await Task.Delay(2000);

        currentHeading = $"{newHeading}!!!";
    }
}

イベント引数

イベント引数の型をサポートするイベントの場合、イベント メソッド定義でイベント パラメーターを指定する必要があるのは、イベントの型がメソッドで使用されている場合のみです。 次の例では、ReportPointerLocation メソッドで MouseEventArgs が使用されています。これにより、ユーザーが UI 内でボタンを選択すると、マウスの座標を報告するメッセージ テキストが設定されます。

Pages/EventHandlerExample3.razor:

@page "/event-handler-example-3"

@for (var i = 0; i < 4; i++)
{
    <p>
        <button @onclick="ReportPointerLocation">
            Where's my mouse pointer for this button?
        </button>
    </p>
}

<p>@mousePointerMessage</p>

@code {
    private string mousePointerMessage;

    private void ReportPointerLocation(MouseEventArgs e)
    {
        mousePointerMessage = $"Mouse coordinates: {e.ScreenX}:{e.ScreenY}";
    }
}

サポートされている EventArgs を次の表に示します。

event クラス ドキュメント オブジェクト モデル (DOM) イベントと注記
クリップボードのトピック ClipboardEventArgs oncut, oncopy, onpaste
ドラッグ DragEventArgs ondrag, ondragstart, ondragenter, ondragleave, ondragover, ondrop, ondragend

DataTransfer および DataTransferItem では、ドラッグされた項目データを保持します。

HTML ドラッグ アンド ドロップ API と共に JS 相互運用を使用し、Blazor アプリにドラッグ アンド ドロップを実装します。
エラー ErrorEventArgs onerror
event EventArgs 全般
onactivate, onbeforeactivate, onbeforedeactivate, ondeactivate, onfullscreenchange, onfullscreenerror, onloadeddata, onloadedmetadata, onpointerlockchange, onpointerlockerror, onreadystatechange, onscroll

クリップボード
onbeforecut, onbeforecopy, onbeforepaste

入力
oninvalid, onreset, onselect, onselectionchange, onselectstart, onsubmit

メディア
oncanplay, oncanplaythrough, oncuechange, ondurationchange, onemptied, onended, onpause, onplay, onplaying, onratechange, onseeked, onseeking, onstalled, onstop, onsuspend, ontimeupdate, onvolumechange, onwaiting

EventHandlers は、イベント名とイベント引数の型の間のマッピングを構成する属性を保持します。
フォーカス FocusEventArgs onfocus, onblur, onfocusin, onfocusout

relatedTarget のサポートは含まれません。
入力 ChangeEventArgs onchange, oninput
キーボード KeyboardEventArgs onkeydown, onkeypress, onkeyup
マウス MouseEventArgs onclick, oncontextmenu, ondblclick, onmousedown, onmouseup, onmouseover, onmousemove, onmouseout
マウス ポインター PointerEventArgs onpointerdown, onpointerup, onpointercancel, onpointermove, onpointerover, onpointerout, onpointerenter, onpointerleave, ongotpointercapture, onlostpointercapture
マウス ホイール WheelEventArgs onwheel, onmousewheel
進行状況 ProgressEventArgs onabort, onload, onloadend, onloadstart, onprogress, ontimeout
タッチ TouchEventArgs ontouchstart, ontouchend, ontouchmove, ontouchenter, ontouchleave, ontouchcancel

TouchPoint は、タッチを検知するデバイス上の単一接触点を表します。

詳細については、ASP.NET Core 参照ソース内の EventArgs クラス (dotnet/aspnetcore main ブランチ) を参照してください

注意

通常、.NET 参照ソースへのドキュメント リンクを使用すると、リポジトリの既定のブランチが読み込まれます。このブランチは、.NET の次回リリースに向けて行われている現在の開発を表します。 特定のリリースのタグを選択するには、[Switch branches or tags](ブランチまたはタグの切り替え) ドロップダウン リストを使います。 詳細については、「ASP.NET Core ソース コードのバージョン タグを選択する方法」 (dotnet/AspNetCore.Docs #26205) を参照してください。

ラムダ式

ラムダ式 は、デリゲート イベント ハンドラーとしてサポートされています。

Pages/EventHandlerExample4.razor:

@page "/event-handler-example-4"

<h1>@heading</h1>

<p>
    <button @onclick="@(e => heading = "New heading!!!")">
        Update heading
    </button>
</p>

@code {
    private string heading = "Initial heading";
}

要素のセットを反復処理するときなど、C# メソッド パラメーターを使用して追加の値に集中すると便利な場合がよくあります。 次の例では、3 つのボタンを作成します。それぞれを押すと、UpdateHeading が呼び出され、次のデータが渡されます。

  • e に対してイベント引数 (MouseEventArgs)。
  • buttonNumber に対してボタン番号。

Pages/EventHandlerExample5.razor:

@page "/event-handler-example-5"

<h1>@heading</h1>

@for (var i = 1; i < 4; i++)
{
    var buttonNumber = i;

    <p>
        <button @onclick="@(e => UpdateHeading(e, buttonNumber))">
            Button #@i
        </button>
    </p>
}

@code {
    private string heading = "Select a button to learn its position";

    private void UpdateHeading(MouseEventArgs e, int buttonNumber)
    {
        heading = $"Selected #{buttonNumber} at {e.ClientX}:{e.ClientY}";
    }
}

ループ内に多数のイベント委任を作成すると、レンダリングのパフォーマンスが低下する可能性があります。 詳しくは、「ASP.NET Core Blazor のパフォーマンスに関するベスト プラクティス」をご覧ください。

前の for ループの例の i など、ラムダ式内で直接ループ変数を使用することは避けてください。 そうしないと、すべてのラムダ式で同じ変数が使用され、すべてのラムダで同じ値が使用されることになります。 変数の値をローカル変数に取得してください。 前の例の場合:

  • ループ変数 ibuttonNumber に割り当てられます。
  • buttonNumber はラムダ式で使用されます。

または、foreach ループと Enumerable.Range を使います。このようにすると上記の問題は発生しません。

@foreach (var buttonNumber in Enumerable.Range(1,3))
{
    <p>
        <button @onclick="@(e => UpdateHeading(e, buttonNumber))">
            Button #@buttonNumber
        </button>
    </p>
}

EventCallback

入れ子になったコンポーネントがある一般的なシナリオでは、子コンポーネントのイベントが発生したときに親コンポーネントのメソッドを実行します。 子コンポーネントで発生する onclick イベントが、一般的なユース ケースです。 コンポーネント間にわたってイベントを公開するには、EventCallback を使用します。 親コンポーネントでは、コールバック メソッドを子コンポーネントの EventCallback に割り当てることができます。

次の Child は、ボタンの onclick ハンドラーがどのように、サンプルの ParentComponent から EventCallback デリゲートを受け取るように設定されているかを示しています。 EventCallbackMouseEventArgs によって型指定されます。これは、周辺機器の onclick イベントに適しています。

Shared/Child.razor:

<p>
    <button @onclick="OnClickCallback">
        Trigger a Parent component method
    </button>
</p>

@code {
    [Parameter]
    public string Title { get; set; }

    [Parameter]
    public RenderFragment ChildContent { get; set; }

    [Parameter]
    public EventCallback<MouseEventArgs> OnClickCallback { get; set; }
}

Parent コンポーネントでは、子の EventCallback<TValue> (OnClickCallback) を ShowMessage メソッドに設定しています。

Pages/Parent.razor:

@page "/parent"

<h1>Parent-child example</h1>

<Child Title="Panel Title from Parent" OnClickCallback="@ShowMessage">
    Content of the child component is supplied by the parent component.
</Child>

<p>@message</p>

@code {
    private string message;

    private void ShowMessage(MouseEventArgs e)
    {
        message = $"Blaze a new trail with Blazor! ({e.ScreenX}:{e.ScreenY})";
    }
}

ChildComponent でボタンが選択されると:

  • Parent コンポーネントの ShowMessage メソッドが呼び出されます。 message が更新されて、Parent コンポーネントに表示されます。
  • コールバックのメソッド (ShowMessage) 内に、StateHasChanged の呼び出しは必要ありません。 StateHasChanged は、子イベントが子の中で実行されるイベント ハンドラーでコンポーネントのレンダリングをトリガーするのと同様に、Parent コンポーネントを再レンダリングするために自動的に呼び出されます。 詳しくは、「ASP.NET Core Razor コンポーネントのレンダリング」をご覧ください。

EventCallbackEventCallback<TValue> では非同期デリゲートを使用できます。 EventCallback は弱く型指定されており、InvokeAsync(Object) では任意の型の引数を渡すことができます。 EventCallback<TValue> は厳密に型指定されており、InvokeAsync(T) では TValue に代入可能な T 引数を渡す必要があります。

<ChildComponent 
    OnClickCallback="@(async () => { await Task.Yield(); messageText = "Blaze It!"; })" />

InvokeAsync を使用して EventCallback または EventCallback<TValue> を呼び出して、Task を待機します。

await OnClickCallback.InvokeAsync(arg);

イベント処理とバインド コンポーネントのパラメーターには、EventCallbackEventCallback<TValue> を使用します。

厳密に型指定された EventCallback<TValue>EventCallback よりも優先します。 EventCallback<TValue> からは、強化されたエラー フィードバックがコンポーネントのユーザーに提供されます。 他の UI イベント ハンドラーと同様に、このイベント パラメーターの指定は省略可能です。 コールバックに渡される値がない場合は、EventCallback を使用します。

既定のアクションを止める

イベントの既定のアクションを防止するには、@on{DOM EVENT}:preventDefault ディレクティブ属性を使用します。ここで、{DOM EVENT} プレースホルダーは、ドキュメント オブジェクト モデル (DOM) イベントです。

入力デバイスでキーが選択され、要素のフォーカスがテキスト ボックス上にあるときは、通常、ブラウザーによってテキスト ボックスにキーの文字が表示されます。 次の例では、@onkeydown:preventDefault ディレクティブ属性を指定することで、既定の動作が止められています。 <input> 要素にフォーカスがある場合、カウンターはキー シーケンス Shift++ が押されるとインクリメントします。 + 文字は、<input> 要素の値に割り当てられていません。 keydown の詳細については、「MDN Web Docs: Document: keydown イベント」を参照してください。

Pages/EventHandlerExample6.razor:

@page "/event-handler-example-6"

<p>
    <input value="@count" @onkeydown="KeyHandler" @onkeydown:preventDefault />
</p>

@code {
    private int count = 0;

    private void KeyHandler(KeyboardEventArgs e)
    {
        if (e.Key == "+")
        {
            count++;
        }
    }
}

値なしで @on{DOM EVENT}:preventDefault 属性を指定することは、@on{DOM EVENT}:preventDefault="true" と同じことになります。

式は、許可されている属性値でもあります。 次の例では、shouldPreventDefaulttrue または false のいずれかに設定される bool フィールドです。

<input @onkeydown:preventDefault="shouldPreventDefault" />

...

@code {
    private bool shouldPreventDefault = true;
}

イベント伝達を停止する

Blazor スクリプト内でイベント伝達を停止するには、@on{DOM EVENT}:stopPropagation ディレクティブ属性を使用します。 {DOM EVENT} プレースホルダーは ドキュメント オブジェクト モデル (DOM) イベントです

stopPropagation ディレクティブ属性の効果は Blazor スコープに限定され、HTML DOM まで拡大されることはありません。 イベントは、それに基づいて Blazor が動作する前に HTML DOM ルートに反映される必要があります。 HTML DOM イベントの伝達を防止するメカニズムについては、次の方法を検討してください。

次の例では、チェックボックスをオンにすると、2 番目の子 <div> からのクリック イベントが親の <div> に伝達されなくなります。 クリック イベントが伝達されると、通常、OnSelectParentDiv メソッドが起動されるので、2 番目の子 <div> を選択すると、チェックボックスがオンになっていない限り、親の <div> メッセージが表示されます。

Pages/EventHandlerExample7.razor:

@page "/event-handler-example-7"

<label>
    <input @bind="stopPropagation" type="checkbox" />
    Stop Propagation
</label>

<div class="m-1 p-1 border border-primary" @onclick="OnSelectParentDiv">
    <h3>Parent div</h3>

    <div class="m-1 p-1 border" @onclick="OnSelectChildDiv">
        Child div that doesn't stop propagation when selected.
    </div>

    <div class="m-1 p-1 border" @onclick="OnSelectChildDiv" 
            @onclick:stopPropagation="stopPropagation">
        Child div that stops propagation when selected.
    </div>
</div>

<p>
    @message
</p>

@code {
    private bool stopPropagation = false;
    private string message; 

    private void OnSelectParentDiv() =>
        message = $"The parent div was selected. {DateTime.Now}";

    private void OnSelectChildDiv() =>
        message = $"A child div was selected. {DateTime.Now}";
}