Control de eventos de Blazor en ASP.NET Core

Especifique los controladores de eventos delegados en el marcado del componente Razor con la sintaxis @on{DOM EVENT}="{DELEGATE}" de Razor:

  • El marcador de posición {DOM EVENT} es un evento de Document Object Model (DOM) (por ejemplo, click).
  • El marcador de posición {DELEGATE} es el controlador de eventos delegado de C#.

Para el control de eventos:

  • Se admiten los controladores de eventos delegados asincrónicos que devuelven Task.
  • Los controladores de eventos delegados desencadenan una representación de la interfaz de usuario de forma automática, por lo que no es necesario llamar a StateHasChanged manualmente.
  • Se registran excepciones.

El código siguiente:

  • Llama al método UpdateHeading cuando se selecciona el botón en la interfaz de usuario.
  • Llama al método CheckChanged cuando se cambia la casilla en la interfaz de usuario.

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}";
    }
}

En el ejemplo siguiente, UpdateHeading:

  • Se llama de forma asincrónica cuando se selecciona el botón.
  • Espera dos segundos antes de actualizar el encabezado.

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}!!!";
    }
}

Argumentos de eventos

Argumentos de eventos integrados

En el caso de los eventos que admiten un tipo de argumento de evento, solo es necesario especificar un parámetro de evento en la definición del método del evento si se usa el tipo de evento en el método. En el ejemplo siguiente, MouseEventArgs se usa en el método ReportPointerLocation para establecer el texto del mensaje que informa de las coordenadas del mouse cuando el usuario selecciona un botón en la interfaz de usuario.

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}";
    }
}

En la tabla siguiente se muestran los valores EventArgs admitidos.

evento Clase Eventos y notas de Document Object Model (DOM)
Portapapeles ClipboardEventArgs oncut, oncopy, onpaste
Arrastrar DragEventArgs ondrag, ondragstart, ondragenter, ondragleave, ondragover, ondrop, ondragend

DataTransfer y DataTransferItem contienen datos de elementos arrastrados.

Implemente la función de arrastrar y colocar en las aplicaciones de Blazor mediante la Interoperabilidad de JS con Drag and Drop API en HTML.
Error ErrorEventArgs onerror
evento EventArgs General
onactivate, onbeforeactivate, onbeforedeactivate, ondeactivate, onfullscreenchange, onfullscreenerror, onloadeddata, onloadedmetadata, onpointerlockchange, onpointerlockerror, onreadystatechange, onscroll

Portapapeles
onbeforecut, onbeforecopy, onbeforepaste

Entrada
oninvalid, onreset, onselect, onselectionchange, onselectstart, onsubmit

Elementos multimedia
oncanplay, oncanplaythrough, oncuechange, ondurationchange, onemptied, onended, onpause, onplay, onplaying, onratechange, onseeked, onseeking, onstalled, onstop, onsuspend, ontimeupdate, ontoggle, onvolumechange, onwaiting

EventHandlers contiene atributos para configurar las asignaciones entre los nombres de evento y los tipos de argumento de evento.
Foco FocusEventArgs onfocus, onblur, onfocusin, onfocusout

No incluye compatibilidad con relatedTarget.
Entrada ChangeEventArgs onchange, oninput
Teclado KeyboardEventArgs onkeydown, onkeypress, onkeyup
Mouse MouseEventArgs onclick, oncontextmenu, ondblclick, onmousedown, onmouseup, onmouseover, onmousemove, onmouseout
Puntero del mouse PointerEventArgs onpointerdown, onpointerup, onpointercancel, onpointermove, onpointerover, onpointerout, onpointerenter, onpointerleave, ongotpointercapture, onlostpointercapture
Rueda del mouse WheelEventArgs onwheel, onmousewheel
Progreso ProgressEventArgs onabort, onload, onloadend, onloadstart, onprogress, ontimeout
Entrada táctil TouchEventArgs ontouchstart, ontouchend, ontouchmove, ontouchenter, ontouchleave, ontouchcancel

TouchPoint representa un único punto de contacto en un dispositivo sensible al tacto.

Para obtener más información, vea los siguientes recursos:

Argumentos de eventos personalizados

Blazor admite argumentos de eventos personalizados, que permiten pasar datos arbitrarios a controladores de eventos de .NET con eventos personalizados.

Configuración general

Los eventos personalizados con argumentos de eventos personalizados generalmente se habilitan con los pasos siguientes.

  1. En JavaScript, defina una función para generar el objeto de argumento de evento personalizado a partir del evento de origen:

    function eventArgsCreator(event) { 
      return {
        customProperty1: 'any value for property 1',
        customProperty2: event.srcElement.value
      };
    }
    
  2. Registre el evento personalizado con el controlador anterior en wwwroot/index.html (Blazor WebAssembly) o Pages/_Layout.cshtml (Blazor Server) inmediatamente después de Blazor <script>:

    <script>
      Blazor.registerCustomEventType('customevent', {
        createEventArgs: eventArgsCreator;
      });
    </script>
    

    Nota

    La llamada a registerCustomEventType se realiza en un script solo una vez por evento.

  3. Defina una clase para los argumentos del evento:

    public class CustomEventArgs : EventArgs
    {
        public string CustomProperty1 {get; set;}
        public string CustomProperty2 {get; set;}
    }
    
  4. Conecte el evento personalizado con los argumentos del evento agregando una anotación de atributo EventHandlerAttribute para el evento personalizado. La clase no requiere miembros:

    [EventHandler("oncustomevent", typeof(CustomEventArgs), enableStopPropagation: true, enablePreventDefault: true)]
    static class EventHandlers
    {
    }
    
  5. Registre el controlador de eventos en uno o varios elementos HTML. Acceda a los datos pasados de JavaScript al método de controlador de delegado:

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

Cada vez que se desencadena el evento personalizado en el DOM, se llama al controlador de eventos con los datos pasados desde JavaScript.

Si se está intentando activar un evento personalizado, bubbles debe habilitarse estableciendo su valor en true. De lo contrario, el evento no alcanza el controlador Blazor para su procesamiento en el método personalizado EventHandlerAttribute de C#. Para obtener más información, vea Creación y activación de eventos (Event), en MDN Web Docs.

Ejemplo de evento de pegado del portapapeles personalizado

En el siguiente ejemplo se recibe un evento de pegado del portapapeles personalizado que incluye la hora de pegado y el texto pegado del usuario.

Declare un nombre personalizado (oncustompaste) para el evento y una clase .NET (CustomPasteEventArgs) para que contenga los argumentos de este evento:

CustomEvents.cs:

[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; }
}

Agregue código JavaScript para proporcionar los datos de la subclase EventArgs. En el archivo wwwroot/index.html o Pages/_Layout.cshtml, agregue la siguiente etiqueta <script> y el contenido inmediatamente después del script Blazor. En el ejemplo siguiente solo se controla el pegado de texto, pero se pueden usar API de JavaScript arbitrarias para tratar con los usuarios que pegan otros tipos de datos, como imágenes.

wwwroot/index.html (Blazor WebAssembly) o Pages/_Layout.cshtml (Blazor Server) inmediatamente después del script Blazor:

<script>
    Blazor.registerCustomEventType('custompaste', {
        browserEventName: 'paste',
        createEventArgs: event => {
            return {
                eventTimestamp: new Date(),
                pastedData: event.clipboardData.getData('text')
            };
        }
    });
</script>

El código anterior, cuando se produce un evento paste nativo, indica al explorador que:

  • Genere un evento custompaste.
  • Proporcione los datos de los argumentos de eventos mediante la lógica personalizada indicada:
    • Para eventTimestamp, se crea una nueva fecha.
    • Para pastedData, se obtienen los datos del portapapeles como texto. Para obtener más información, consulte ClipboardEvent.clipboardData, en MDN Web Docs.

Las convenciones de los nombres de eventos difieren entre .NET y JavaScript:

  • En .NET, los nombres de eventos tienen el prefijo "on".
  • En JavaScript, los nombres de eventos no tienen prefijo.

En un componente Razor, asocie el controlador personalizado a un elemento.

Pages/CustomPasteArguments.razor:

@page "/custom-paste-arguments"

<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}";
    }
}

Expresiones lambda

Las expresiones lambda se admiten como controladores de eventos delegados.

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";
}

A menudo resulta práctico cerrar los valores adicionales utilizando parámetros de C#, como al recorrer en iteración un conjunto de elementos. En el ejemplo siguiente se crean tres botones, cada uno de los cuales llama a UpdateHeading y pasa los datos siguientes:

  • Un argumento de evento (MouseEventArgs) en e.
  • El número de botón en 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}";
    }
}

Nota

No use una variable de bucle directamente en una expresión lambda (como i en el ejemplo de bucle for anterior). de lo contrario, todas las expresiones lambda usarán la misma variable, con lo cual se usará el mismo valor en todas las expresiones lambda. Capture siempre el valor de la variable en una variable local y úsela. En el ejemplo anterior:

  • La variable de bucle i se asigna a buttonNumber.
  • buttonNumber se usa en la expresión lambda.

La creación de un gran número de delegados de eventos en un bucle puede provocar un rendimiento de representación deficiente. Para obtener más información, vea Procedimientos recomendados de rendimiento de Blazor en ASP.NET Core.

EventCallback

Un escenario común con los componentes anidados es ejecutar un método de un componente primario cuando se produce un evento de un componente secundario. Un caso habitual es un evento onclick que se produce en el componente secundario. Para exponer eventos entre componentes, use un elemento EventCallback. Un componente primario puede asignar un método de devolución de llamada al elemento EventCallback de un componente secundario.

El siguiente componente Child indica cómo se configura el controlador onclick de un botón para recibir un elemento EventCallback delegado del elemento ParentComponent de la muestra. El elemento EventCallback se escribe con MouseEventArgs, que es adecuado para un evento onclick relativo a un dispositivo periférico.

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; }
}

El componente Parent establece el elemento EventCallback<TValue> (OnClickCallback) del elemento secundario en su método 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})";
    }
}

Cuando el botón se selecciona en ChildComponent:

  • Se llama al método ShowMessage del componente Parent. message se actualiza y se muestra en el componente Parent.
  • No se requiere una llamada a StateHasChanged en el método de la devolución de llamada (ShowMessage). Se llama a StateHasChanged de forma automática para volver a representar el componente Parent, del mismo modo que los eventos secundarios desencadenan la nueva representación de los controladores de eventos que se ejecutan dentro del elemento secundario. Para obtener más información, vea Representación de componentes de Blazor de ASP.NET Core.

EventCallback y EventCallback<TValue> permiten delegados asincrónicos. EventCallback tiene un establecimiento flexible de tipos y permite pasar cualquier argumento de tipo en InvokeAsync(Object). EventCallback<TValue> tiene un establecimiento inflexible de tipos y requiere pasar un argumento T en InvokeAsync(T) que se puede asignar a TValue.

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

Invoque EventCallback o EventCallback<TValue> con InvokeAsync y espere a Task:

await OnClickCallback.InvokeAsync(arg);

Use EventCallback y EventCallback<TValue> para el control de eventos y el enlace de parámetros de componentes.

Se prefiere EventCallback<TValue> (fuertemente tipado) a EventCallback. EventCallback<TValue> proporciona mejores comentarios de errores a los usuarios del componente. Como sucede con otros controladores de eventos de la interfaz de usuario, la especificación del parámetro de evento es opcional. Use EventCallback cuando no se pase ningún valor a la devolución de llamada.

Bloqueo de acciones predeterminadas

Use el atributo @on{DOM EVENT}:preventDefault de directiva para evitar la acción predeterminada de un evento, donde el marcador de posición {DOM EVENT} es un evento Document Object Model (DOM).

Si se selecciona una tecla en un dispositivo de entrada y el foco del elemento está en un cuadro de texto, un explorador muestra normalmente el carácter de la tecla en el cuadro de texto. En el ejemplo siguiente, el comportamiento predeterminado se evita mediante la especificación del atributo de directiva @onkeydown:preventDefault. Cuando el foco está en el elemento <input>, el contador se incrementa con la secuencia de teclas Mayús++. El carácter + no está asignado al valor del elemento <input>. Para más información sobre keydown, vea Evento 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++;
        }
    }
}

Especificar el atributo @on{DOM EVENT}:preventDefault sin un valor es equivalente a @on{DOM EVENT}:preventDefault="true".

Una expresión también es un valor permitido del atributo. En el ejemplo siguiente, shouldPreventDefault es un campo bool establecido en true o false:

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

...

@code {
    private bool shouldPreventDefault = true;
}

Detención de la propagación de eventos

Use el atributo @on{DOM EVENT}:stopPropagation de directiva para impedir la propagación, donde el marcador de posición {DOM EVENT} es un evento Document Object Model (DOM).

En el ejemplo siguiente, al activar la casilla se impide que los eventos de clic del elemento secundario <div> se propaguen al elemento principal <div>. Dado que los eventos de clic propagados normalmente activan el método OnSelectParentDiv, el hecho de seleccionar el segundo elemento secundario <div> hará que se muestre el mensaje "div" primario, a menos que la casilla esté activada.

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}";
}

Foco en un elemento

Llame a FocusAsync en una referencia de elemento para centrar el foco en un elemento del código. En el ejemplo siguiente, seleccione el botón para centrar el foco en el elemento <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();
    }
}

Especifique los controladores de eventos delegados en el marcado del componente Razor con la sintaxis @on{DOM EVENT}="{DELEGATE}" de Razor:

  • El marcador de posición {DOM EVENT} es un evento de Document Object Model (DOM) (por ejemplo, click).
  • El marcador de posición {DELEGATE} es el controlador de eventos delegado de C#.

Para el control de eventos:

  • Se admiten los controladores de eventos delegados asincrónicos que devuelven Task.
  • Los controladores de eventos delegados desencadenan una representación de la interfaz de usuario de forma automática, por lo que no es necesario llamar a StateHasChanged manualmente.
  • Se registran excepciones.

El código siguiente:

  • Llama al método UpdateHeading cuando se selecciona el botón en la interfaz de usuario.
  • Llama al método CheckChanged cuando se cambia la casilla en la interfaz de usuario.

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}";
    }
}

En el ejemplo siguiente, UpdateHeading:

  • Se llama de forma asincrónica cuando se selecciona el botón.
  • Espera dos segundos antes de actualizar el encabezado.

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}!!!";
    }
}

Argumentos de eventos

En el caso de los eventos que admiten un tipo de argumento de evento, solo es necesario especificar un parámetro de evento en la definición del método del evento si se usa el tipo de evento en el método. En el ejemplo siguiente, MouseEventArgs se usa en el método ReportPointerLocation para establecer el texto del mensaje que informa de las coordenadas del mouse cuando el usuario selecciona un botón en la interfaz de usuario.

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}";
    }
}

En la tabla siguiente se muestran los valores EventArgs admitidos.

evento Clase Eventos y notas de Document Object Model (DOM)
Portapapeles ClipboardEventArgs oncut, oncopy, onpaste
Arrastrar DragEventArgs ondrag, ondragstart, ondragenter, ondragleave, ondragover, ondrop, ondragend

DataTransfer y DataTransferItem contienen datos de elementos arrastrados.

Implemente la función de arrastrar y colocar en las aplicaciones de Blazor mediante la Interoperabilidad de JS con Drag and Drop API en HTML.
Error ErrorEventArgs onerror
evento EventArgs General
onactivate, onbeforeactivate, onbeforedeactivate, ondeactivate, onfullscreenchange, onfullscreenerror, onloadeddata, onloadedmetadata, onpointerlockchange, onpointerlockerror, onreadystatechange, onscroll

Portapapeles
onbeforecut, onbeforecopy, onbeforepaste

Entrada
oninvalid, onreset, onselect, onselectionchange, onselectstart, onsubmit

Elementos multimedia
oncanplay, oncanplaythrough, oncuechange, ondurationchange, onemptied, onended, onpause, onplay, onplaying, onratechange, onseeked, onseeking, onstalled, onstop, onsuspend, ontimeupdate, ontoggle, onvolumechange, onwaiting

EventHandlers contiene atributos para configurar las asignaciones entre los nombres de evento y los tipos de argumento de evento.
Foco FocusEventArgs onfocus, onblur, onfocusin, onfocusout

No incluye compatibilidad con relatedTarget.
Entrada ChangeEventArgs onchange, oninput
Teclado KeyboardEventArgs onkeydown, onkeypress, onkeyup
Mouse MouseEventArgs onclick, oncontextmenu, ondblclick, onmousedown, onmouseup, onmouseover, onmousemove, onmouseout
Puntero del mouse PointerEventArgs onpointerdown, onpointerup, onpointercancel, onpointermove, onpointerover, onpointerout, onpointerenter, onpointerleave, ongotpointercapture, onlostpointercapture
Rueda del mouse WheelEventArgs onwheel, onmousewheel
Progreso ProgressEventArgs onabort, onload, onloadend, onloadstart, onprogress, ontimeout
Entrada táctil TouchEventArgs ontouchstart, ontouchend, ontouchmove, ontouchenter, ontouchleave, ontouchcancel

TouchPoint representa un único punto de contacto en un dispositivo sensible al tacto.

Para obtener más información, vea los siguientes recursos:

Expresiones lambda

Las expresiones lambda se admiten como controladores de eventos delegados.

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";
}

A menudo resulta práctico cerrar los valores adicionales utilizando parámetros de C#, como al recorrer en iteración un conjunto de elementos. En el ejemplo siguiente se crean tres botones, cada uno de los cuales llama a UpdateHeading y pasa los datos siguientes:

  • Un argumento de evento (MouseEventArgs) en e.
  • El número de botón en 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}";
    }
}

Nota

No use una variable de bucle directamente en una expresión lambda (como i en el ejemplo de bucle for anterior). de lo contrario, todas las expresiones lambda usarán la misma variable, con lo cual se usará el mismo valor en todas las expresiones lambda. Capture siempre el valor de la variable en una variable local y úsela. En el ejemplo anterior:

  • La variable de bucle i se asigna a buttonNumber.
  • buttonNumber se usa en la expresión lambda.

La creación de un gran número de delegados de eventos en un bucle puede provocar un rendimiento de representación deficiente. Para obtener más información, vea Procedimientos recomendados de rendimiento de Blazor en ASP.NET Core.

EventCallback

Un escenario común con los componentes anidados es ejecutar un método de un componente primario cuando se produce un evento de un componente secundario. Un caso habitual es un evento onclick que se produce en el componente secundario. Para exponer eventos entre componentes, use un elemento EventCallback. Un componente primario puede asignar un método de devolución de llamada al elemento EventCallback de un componente secundario.

El siguiente componente Child indica cómo se configura el controlador onclick de un botón para recibir un elemento EventCallback delegado del elemento ParentComponent de la muestra. El elemento EventCallback se escribe con MouseEventArgs, que es adecuado para un evento onclick relativo a un dispositivo periférico.

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; }
}

El componente Parent establece el elemento EventCallback<TValue> (OnClickCallback) del elemento secundario en su método 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})";
    }
}

Cuando el botón se selecciona en ChildComponent:

  • Se llama al método ShowMessage del componente Parent. message se actualiza y se muestra en el componente Parent.
  • No se requiere una llamada a StateHasChanged en el método de la devolución de llamada (ShowMessage). Se llama a StateHasChanged de forma automática para volver a representar el componente Parent, del mismo modo que los eventos secundarios desencadenan la nueva representación de los controladores de eventos que se ejecutan dentro del elemento secundario. Para obtener más información, vea Representación de componentes de Blazor de ASP.NET Core.

EventCallback y EventCallback<TValue> permiten delegados asincrónicos. EventCallback tiene un establecimiento flexible de tipos y permite pasar cualquier argumento de tipo en InvokeAsync(Object). EventCallback<TValue> tiene un establecimiento inflexible de tipos y requiere pasar un argumento T en InvokeAsync(T) que se puede asignar a TValue.

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

Invoque EventCallback o EventCallback<TValue> con InvokeAsync y espere a Task:

await OnClickCallback.InvokeAsync(arg);

Use EventCallback y EventCallback<TValue> para el control de eventos y el enlace de parámetros de componentes.

Se prefiere EventCallback<TValue> (fuertemente tipado) a EventCallback. EventCallback<TValue> proporciona mejores comentarios de errores a los usuarios del componente. Como sucede con otros controladores de eventos de la interfaz de usuario, la especificación del parámetro de evento es opcional. Use EventCallback cuando no se pase ningún valor a la devolución de llamada.

Bloqueo de acciones predeterminadas

Use el atributo @on{DOM EVENT}:preventDefault de directiva para evitar la acción predeterminada de un evento, donde el marcador de posición {DOM EVENT} es un evento Document Object Model (DOM).

Si se selecciona una tecla en un dispositivo de entrada y el foco del elemento está en un cuadro de texto, un explorador muestra normalmente el carácter de la tecla en el cuadro de texto. En el ejemplo siguiente, el comportamiento predeterminado se evita mediante la especificación del atributo de directiva @onkeydown:preventDefault. Cuando el foco está en el elemento <input>, el contador se incrementa con la secuencia de teclas Mayús++. El carácter + no está asignado al valor del elemento <input>. Para más información sobre keydown, vea Evento 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++;
        }
    }
}

Especificar el atributo @on{DOM EVENT}:preventDefault sin un valor es equivalente a @on{DOM EVENT}:preventDefault="true".

Una expresión también es un valor permitido del atributo. En el ejemplo siguiente, shouldPreventDefault es un campo bool establecido en true o false:

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

...

@code {
    private bool shouldPreventDefault = true;
}

Detención de la propagación de eventos

Use el atributo @on{DOM EVENT}:stopPropagation de directiva para impedir la propagación, donde el marcador de posición {DOM EVENT} es un evento Document Object Model (DOM).

En el ejemplo siguiente, al activar la casilla se impide que los eventos de clic del elemento secundario <div> se propaguen al elemento principal <div>. Dado que los eventos de clic propagados normalmente activan el método OnSelectParentDiv, el hecho de seleccionar el segundo elemento secundario <div> hará que se muestre el mensaje "div" primario, a menos que la casilla esté activada.

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}";
}

Foco en un elemento

Llame a FocusAsync en una referencia de elemento para centrar el foco en un elemento del código. En el ejemplo siguiente, seleccione el botón para centrar el foco en el elemento <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();
    }
}

Especifique los controladores de eventos delegados en el marcado del componente Razor con la sintaxis @on{DOM EVENT}="{DELEGATE}" de Razor:

  • El marcador de posición {DOM EVENT} es un evento de Document Object Model (DOM) (por ejemplo, click).
  • El marcador de posición {DELEGATE} es el controlador de eventos delegado de C#.

Para el control de eventos:

  • Se admiten los controladores de eventos delegados asincrónicos que devuelven Task.
  • Los controladores de eventos delegados desencadenan una representación de la interfaz de usuario de forma automática, por lo que no es necesario llamar a StateHasChanged manualmente.
  • Se registran excepciones.

El código siguiente:

  • Llama al método UpdateHeading cuando se selecciona el botón en la interfaz de usuario.
  • Llama al método CheckChanged cuando se cambia la casilla en la interfaz de usuario.

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}";
    }
}

En el ejemplo siguiente, UpdateHeading:

  • Se llama de forma asincrónica cuando se selecciona el botón.
  • Espera dos segundos antes de actualizar el encabezado.

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}!!!";
    }
}

Argumentos de eventos

En el caso de los eventos que admiten un tipo de argumento de evento, solo es necesario especificar un parámetro de evento en la definición del método del evento si se usa el tipo de evento en el método. En el ejemplo siguiente, MouseEventArgs se usa en el método ReportPointerLocation para establecer el texto del mensaje que informa de las coordenadas del mouse cuando el usuario selecciona un botón en la interfaz de usuario.

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}";
    }
}

En la tabla siguiente se muestran los valores EventArgs admitidos.

evento Clase Eventos y notas de Document Object Model (DOM)
Portapapeles ClipboardEventArgs oncut, oncopy, onpaste
Arrastrar DragEventArgs ondrag, ondragstart, ondragenter, ondragleave, ondragover, ondrop, ondragend

DataTransfer y DataTransferItem contienen datos de elementos arrastrados.

Implemente la función de arrastrar y colocar en las aplicaciones de Blazor mediante la Interoperabilidad de JS con Drag and Drop API en HTML.
Error ErrorEventArgs onerror
evento EventArgs General
onactivate, onbeforeactivate, onbeforedeactivate, ondeactivate, onfullscreenchange, onfullscreenerror, onloadeddata, onloadedmetadata, onpointerlockchange, onpointerlockerror, onreadystatechange, onscroll

Portapapeles
onbeforecut, onbeforecopy, onbeforepaste

Entrada
oninvalid, onreset, onselect, onselectionchange, onselectstart, onsubmit

Elementos multimedia
oncanplay, oncanplaythrough, oncuechange, ondurationchange, onemptied, onended, onpause, onplay, onplaying, onratechange, onseeked, onseeking, onstalled, onstop, onsuspend, ontimeupdate, onvolumechange, onwaiting

EventHandlers contiene atributos para configurar las asignaciones entre los nombres de evento y los tipos de argumento de evento.
Foco FocusEventArgs onfocus, onblur, onfocusin, onfocusout

No incluye compatibilidad con relatedTarget.
Entrada ChangeEventArgs onchange, oninput
Teclado KeyboardEventArgs onkeydown, onkeypress, onkeyup
Mouse MouseEventArgs onclick, oncontextmenu, ondblclick, onmousedown, onmouseup, onmouseover, onmousemove, onmouseout
Puntero del mouse PointerEventArgs onpointerdown, onpointerup, onpointercancel, onpointermove, onpointerover, onpointerout, onpointerenter, onpointerleave, ongotpointercapture, onlostpointercapture
Rueda del mouse WheelEventArgs onwheel, onmousewheel
Progreso ProgressEventArgs onabort, onload, onloadend, onloadstart, onprogress, ontimeout
Entrada táctil TouchEventArgs ontouchstart, ontouchend, ontouchmove, ontouchenter, ontouchleave, ontouchcancel

TouchPoint representa un único punto de contacto en un dispositivo sensible al tacto.

Para obtener más información, vea los siguientes recursos:

Expresiones lambda

Las expresiones lambda se admiten como controladores de eventos delegados.

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";
}

A menudo resulta práctico cerrar los valores adicionales utilizando parámetros de C#, como al recorrer en iteración un conjunto de elementos. En el ejemplo siguiente se crean tres botones, cada uno de los cuales llama a UpdateHeading y pasa los datos siguientes:

  • Un argumento de evento (MouseEventArgs) en e.
  • El número de botón en 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}";
    }
}

Nota

No use una variable de bucle directamente en una expresión lambda (como i en el ejemplo de bucle for anterior). de lo contrario, todas las expresiones lambda usarán la misma variable, con lo cual se usará el mismo valor en todas las expresiones lambda. Capture siempre el valor de la variable en una variable local y úsela. En el ejemplo anterior:

  • La variable de bucle i se asigna a buttonNumber.
  • buttonNumber se usa en la expresión lambda.

La creación de un gran número de delegados de eventos en un bucle puede provocar un rendimiento de representación deficiente. Para obtener más información, vea Procedimientos recomendados de rendimiento de Blazor en ASP.NET Core.

EventCallback

Un escenario común con los componentes anidados es ejecutar un método de un componente primario cuando se produce un evento de un componente secundario. Un caso habitual es un evento onclick que se produce en el componente secundario. Para exponer eventos entre componentes, use un elemento EventCallback. Un componente primario puede asignar un método de devolución de llamada al elemento EventCallback de un componente secundario.

El siguiente componente Child indica cómo se configura el controlador onclick de un botón para recibir un elemento EventCallback delegado del elemento ParentComponent de la muestra. El elemento EventCallback se escribe con MouseEventArgs, que es adecuado para un evento onclick relativo a un dispositivo periférico.

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; }
}

El componente Parent establece el elemento EventCallback<TValue> (OnClickCallback) del elemento secundario en su método 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})";
    }
}

Cuando el botón se selecciona en ChildComponent:

  • Se llama al método ShowMessage del componente Parent. message se actualiza y se muestra en el componente Parent.
  • No se requiere una llamada a StateHasChanged en el método de la devolución de llamada (ShowMessage). Se llama a StateHasChanged de forma automática para volver a representar el componente Parent, del mismo modo que los eventos secundarios desencadenan la nueva representación de los controladores de eventos que se ejecutan dentro del elemento secundario. Para obtener más información, vea Representación de componentes de Blazor de ASP.NET Core.

EventCallback y EventCallback<TValue> permiten delegados asincrónicos. EventCallback tiene un establecimiento flexible de tipos y permite pasar cualquier argumento de tipo en InvokeAsync(Object). EventCallback<TValue> tiene un establecimiento inflexible de tipos y requiere pasar un argumento T en InvokeAsync(T) que se puede asignar a TValue.

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

Invoque EventCallback o EventCallback<TValue> con InvokeAsync y espere a Task:

await OnClickCallback.InvokeAsync(arg);

Use EventCallback y EventCallback<TValue> para el control de eventos y el enlace de parámetros de componentes.

Se prefiere EventCallback<TValue> (fuertemente tipado) a EventCallback. EventCallback<TValue> proporciona mejores comentarios de errores a los usuarios del componente. Como sucede con otros controladores de eventos de la interfaz de usuario, la especificación del parámetro de evento es opcional. Use EventCallback cuando no se pase ningún valor a la devolución de llamada.

Bloqueo de acciones predeterminadas

Use el atributo @on{DOM EVENT}:preventDefault de directiva para evitar la acción predeterminada de un evento, donde el marcador de posición {DOM EVENT} es un evento Document Object Model (DOM).

Si se selecciona una tecla en un dispositivo de entrada y el foco del elemento está en un cuadro de texto, un explorador muestra normalmente el carácter de la tecla en el cuadro de texto. En el ejemplo siguiente, el comportamiento predeterminado se evita mediante la especificación del atributo de directiva @onkeydown:preventDefault. Cuando el foco está en el elemento <input>, el contador se incrementa con la secuencia de teclas Mayús++. El carácter + no está asignado al valor del elemento <input>. Para más información sobre keydown, vea Evento 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++;
        }
    }
}

Especificar el atributo @on{DOM EVENT}:preventDefault sin un valor es equivalente a @on{DOM EVENT}:preventDefault="true".

Una expresión también es un valor permitido del atributo. En el ejemplo siguiente, shouldPreventDefault es un campo bool establecido en true o false:

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

...

@code {
    private bool shouldPreventDefault = true;
}

Detención de la propagación de eventos

Use el atributo @on{DOM EVENT}:stopPropagation de directiva para impedir la propagación, donde el marcador de posición {DOM EVENT} es un evento Document Object Model (DOM).

En el ejemplo siguiente, al activar la casilla se impide que los eventos de clic del elemento secundario <div> se propaguen al elemento principal <div>. Dado que los eventos de clic propagados normalmente activan el método OnSelectParentDiv, el hecho de seleccionar el segundo elemento secundario <div> hará que se muestre el mensaje "div" primario, a menos que la casilla esté activada.

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}";
}