AspNetCore.Docs/aspnetcore/blazor/event-handling.md

11 KiB
Raw Blame History

title author description monikerRange ms.author ms.custom ms.date no-loc uid
ASP.NET Core Blazor event handling guardrex Learn about Blazor's event handling features, including event argument types, event callbacks, and managing default browser events. >= aspnetcore-3.1 riande mvc 03/16/2020
Blazor
SignalR
blazor/event-handling

ASP.NET Core Blazor event handling

By Luke Latham and Daniel Roth

Razor components provide event handling features. For an HTML element attribute named @on{EVENT} (for example, @onclick) with a delegate-typed value, a Razor component treats the attribute's value as an event handler.

The following code calls the UpdateHeading method when the button is selected in the UI:

<button class="btn btn-primary" @onclick="UpdateHeading">
    Update heading
</button>

@code {
    private void UpdateHeading(MouseEventArgs e)
    {
        ...
    }
}

The following code calls the CheckChanged method when the check box is changed in the UI:

<input type="checkbox" class="form-check-input" @onchange="CheckChanged" />

@code {
    private void CheckChanged()
    {
        ...
    }
}

Event handlers can also be asynchronous and return a xref:System.Threading.Tasks.Task. There's no need to manually call StateHasChanged. Exceptions are logged when they occur.

In the following example, UpdateHeading is called asynchronously when the button is selected:

<button class="btn btn-primary" @onclick="UpdateHeading">
    Update heading
</button>

@code {
    private async Task UpdateHeading(MouseEventArgs e)
    {
        ...
    }
}

Event argument types

For some events, event argument types are permitted. Specifying an event type in the method call is only necessary if the event type is used in the method.

Supported EventArgs are shown in the following table.

Event Class DOM events and notes
Clipboard ClipboardEventArgs oncut, oncopy, onpaste
Drag DragEventArgs ondrag, ondragstart, ondragenter, ondragleave, ondragover, ondrop, ondragend

DataTransfer and DataTransferItem hold dragged item data.
Error ErrorEventArgs onerror
Event EventArgs General
onactivate, onbeforeactivate, onbeforedeactivate, ondeactivate, onended, onfullscreenchange, onfullscreenerror, onloadeddata, onloadedmetadata, onpointerlockchange, onpointerlockerror, onreadystatechange, onscroll

Clipboard
onbeforecut, onbeforecopy, onbeforepaste

Input
oninvalid, onreset, onselect, onselectionchange, onselectstart, onsubmit

Media
oncanplay, oncanplaythrough, oncuechange, ondurationchange, onemptied, onpause, onplay, onplaying, onratechange, onseeked, onseeking, onstalled, onstop, onsuspend, ontimeupdate, onvolumechange, onwaiting
Focus FocusEventArgs onfocus, onblur, onfocusin, onfocusout

Doesn't include support for relatedTarget.
Input ChangeEventArgs onchange, oninput
Keyboard KeyboardEventArgs onkeydown, onkeypress, onkeyup
Mouse MouseEventArgs onclick, oncontextmenu, ondblclick, onmousedown, onmouseup, onmouseover, onmousemove, onmouseout
Mouse pointer PointerEventArgs onpointerdown, onpointerup, onpointercancel, onpointermove, onpointerover, onpointerout, onpointerenter, onpointerleave, ongotpointercapture, onlostpointercapture
Mouse wheel WheelEventArgs onwheel, onmousewheel
Progress ProgressEventArgs onabort, onload, onloadend, onloadstart, onprogress, ontimeout
Touch TouchEventArgs ontouchstart, ontouchend, ontouchmove, ontouchenter, ontouchleave, ontouchcancel

TouchPoint represents a single contact point on a touch-sensitive device.

For more information, see the following resources:

Lambda expressions

Lambda expressions can also be used:

<button @onclick="@(e => Console.WriteLine("Hello, world!"))">Say hello</button>

It's often convenient to close over additional values, such as when iterating over a set of elements. The following example creates three buttons, each of which calls UpdateHeading passing an event argument (MouseEventArgs) and its button number (buttonNumber) when selected in the UI:

<h2>@_message</h2>

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

    <button class="btn btn-primary"
            @onclick="@(e => UpdateHeading(e, buttonNumber))">
        Button #@i
    </button>
}

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

    private void UpdateHeading(MouseEventArgs e, int buttonNumber)
    {
        _message = $"You selected Button #{buttonNumber} at " +
            $"mouse position: {e.ClientX} X {e.ClientY}.";
    }
}

[!NOTE] Do not use the loop variable (i) in a for loop directly in a lambda expression. Otherwise the same variable is used by all lambda expressions causing i's value to be the same in all lambdas. Always capture its value in a local variable (buttonNumber in the preceding example) and then use it.

EventCallback

A common scenario with nested components is the desire to run a parent component's method when a child component event occurs—for example, when an onclick event occurs in the child. To expose events across components, use an EventCallback. A parent component can assign a callback method to a child component's EventCallback.

The ChildComponent in the sample app (Components/ChildComponent.razor) demonstrates how a button's onclick handler is set up to receive an EventCallback delegate from the sample's ParentComponent. The EventCallback is typed with MouseEventArgs, which is appropriate for an onclick event from a peripheral device:

[!code-razor]

The ParentComponent sets the child's EventCallback<T> (OnClickCallback) to its ShowMessage method.

Pages/ParentComponent.razor:

@page "/ParentComponent"

<h1>Parent-child example</h1>

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

<p><b>@_messageText</b></p>

@code {
    private string _messageText;

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

When the button is selected in the ChildComponent:

  • The ParentComponent's ShowMessage method is called. _messageText is updated and displayed in the ParentComponent.
  • A call to StateHasChanged isn't required in the callback's method (ShowMessage). StateHasChanged is called automatically to rerender the ParentComponent, just as child events trigger component rerendering in event handlers that execute within the child.

EventCallback and EventCallback<T> permit asynchronous delegates. EventCallback<T> is strongly typed and requires a specific argument type. EventCallback is weakly typed and allows any argument type.

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

Invoke an EventCallback or EventCallback<T> with InvokeAsync and await the xref:System.Threading.Tasks.Task:

await callback.InvokeAsync(arg);

Use EventCallback and EventCallback<T> for event handling and binding component parameters.

Prefer the strongly typed EventCallback<T> over EventCallback. EventCallback<T> provides better error feedback to users of the component. Similar to other UI event handlers, specifying the event parameter is optional. Use EventCallback when there's no value passed to the callback.

Prevent default actions

Use the @on{EVENT}:preventDefault directive attribute to prevent the default action for an event.

When a key is selected on an input device and the element focus is on a text box, a browser normally displays the key's character in the text box. In the following example, the default behavior is prevented by specifying the @onkeypress:preventDefault directive attribute. The counter increments, and the + key isn't captured into the <input> element's value:

<input value="@_count" @onkeypress="KeyHandler" @onkeypress:preventDefault />

@code {
    private int _count = 0;

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

Specifying the @on{EVENT}:preventDefault attribute without a value is equivalent to @on{EVENT}:preventDefault="true".

The value of the attribute can also be an expression. In the following example, _shouldPreventDefault is a bool field set to either true or false:

<input @onkeypress:preventDefault="_shouldPreventDefault" />

An event handler isn't required to prevent the default action. The event handler and prevent default action scenarios can be used independently.

Stop event propagation

Use the @on{EVENT}:stopPropagation directive attribute to stop event propagation.

In the following example, selecting the check box prevents click events from the second child <div> from propagating to the parent <div>:

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

<div @onclick="OnSelectParentDiv">
    <h3>Parent div</h3>

    <div @onclick="OnSelectChildDiv">
        Child div that doesn't stop propagation when selected.
    </div>

    <div @onclick="OnSelectChildDiv" @onclick:stopPropagation="_stopPropagation">
        Child div that stops propagation when selected.
    </div>
</div>

@code {
    private bool _stopPropagation = false;

    private void OnSelectParentDiv() => 
        Console.WriteLine($"The parent div was selected. {DateTime.Now}");
    private void OnSelectChildDiv() => 
        Console.WriteLine($"A child div was selected. {DateTime.Now}");
}