Blazor Essentials: su guía paso a paso
Primeros pasos con Blazor
Blazor se está convirtiendo en uno de los marcos más populares y utilizados para el desarrollo de aplicaciones web actuales. En esencia, representa un marco web .NET que le permite crear aplicaciones de página única (SPA) del lado del cliente utilizando C#, sintaxis Razor y HTML. Hay muchas razones para comenzar a usarlo en su próximo proyecto, ya que ofrece toneladas de beneficios, como arquitectura basada en componentes, elementos de interfaz de usuario que se pueden compartir entre páginas, interoperabilidad de JavaScript y muchos más.
Para comprender mejor cómo funcionan Blazor e Ignite UI for Blazor, creamos esta Guía esencial de Quick Blazor con ejemplos, fragmentos de código y casos de uso.
Esenciales Blazor
¿Qué es Blazor?
Blazor es un framework web .NET que nos permite crear aplicaciones del lado del cliente usando C#, sintaxis Razor y HTML. Nos permite crear una aplicación de página única (SPA) rica y moderna, usando C#, y ejecutarla en el navegador de nuestra elección.
El nombre "Blazor" proviene de la capacidad del marco para ejecutar C# y Razor en el navegador. La combinación de "navegador" y "Razor" nos da el nombre "Blazor".
¿Por qué deberíamos utilizar Blazor?
- Blazor nos permite crear una interfaz de usuario rica e interactiva utilizando C#, un lenguaje moderno y rico en funciones.
- Podemos reutilizar la lógica de la aplicación compartiéndola tanto con el cliente como con el servidor. Nos permite tener una experiencia de desarrollo .NET full-stack.
- Podemos utilizar las API y herramientas .NET existentes para crear aplicaciones web enriquecidas.
- Blazor es compatible con Visual Studio y Visual Studio Code. Esto proporciona una excelente experiencia de desarrollo .NET en múltiples plataformas, incluidas Linux, Windows y Mac.
- Compatible con todos los navegadores modernos, incluidos los navegadores móviles.
- Es un marco de código abierto con un gran apoyo de la comunidad.
- Fácil de alojar la aplicación mediante IIS, el servicio de aplicaciones Azure y Docker.
Características de Blazor
- Arquitectura basada en componentes: Blazor nos proporciona una arquitectura basada en componentes para crear una interfaz de usuario rica y componible.
- Diseños: podemos compartir elementos comunes de la interfaz de usuario (por ejemplo, menús) entre páginas utilizando la función de diseños.
- Interoperabilidad de JavaScript: Esto nos permite invocar un método C# desde JavaScript, y podemos llamar a una función o API de JavaScript desde código C#.
- Enrutamiento: podemos redirigir la solicitud del cliente de un componente a otro con la ayuda del enrutamiento.
- Formularios y validación: podemos crear formularios interactivos para manejar las entradas del usuario y aplicar técnicas de validación para manejar cualquier error en el formulario.
- Gestión de estado: podemos conservar el estado de la aplicación para el usuario en la memoria del navegador. Sin embargo, si el usuario vuelve a abrir su navegador o recarga la página, el estado de usuario guardado en la memoria del navegador se pierde.
- Globalización y localización: una aplicación Blazor puede ser accesible para usuarios en múltiples culturas e idiomas. Esto nos permite ampliar el alcance de nuestra aplicación a una audiencia mundial.
- Aplicaciones web progresivas: Podemos crear una aplicación Blazor como una aplicación web progresiva. Esto permitirá que la aplicación Blazor funcione sin conexión y se cargue instantáneamente independientemente de la velocidad de la red del usuario.
- Carga diferida: La carga diferida nos permite retrasar la carga de algunos ensamblajes de aplicaciones hasta que sean necesarios. Esto mejorará el rendimiento de inicio de la aplicación.
- Depuración: podemos depurar las aplicaciones Blazor WebAssembly en navegadores basados en Chromium como Microsoft Edge y Google Chrome. Y además, el soporte de depuración en Firefox está disponible (actualmente se encuentra en la etapa de vista previa). También podemos depurar la aplicación en Visual Studio y Visual Studio Code IDE.
Modelo de alojamiento Blazor
El modelo de componentes de Blazor es responsable de calcular los cambios de la interfaz de usuario. Sin embargo, podemos usar diferentes renderizadores para controlar cómo se muestra y actualiza la interfaz de usuario. Estos renderizadores se conocen como modelos de alojamiento.
Blazor admite dos modelos de hosting
- Asamblea web Blazor
- Servidor Blazor
Modelo de ejecución del servidor Blazor
¿Qué es el servidor Blazor?
El modelo de alojamiento del servidor Blazor permite que la aplicación Blazor se ejecute en el servidor además del tiempo de ejecución completo de .NET.
¿Cómo funciona el servidor Blazor?
El modelo de ejecución del servidor Blazor se muestra en la siguiente imagen:
Cuando el usuario carga la aplicación, se descarga un pequeño archivo JavaScript (blazor.server.js) en el navegador que establece una conexión SignalR bidireccional en tiempo real con el servidor.
Cualquier interacción del usuario con la aplicación se transmite al servidor a través de la conexión SignalR utilizando el protocolo WebSocket de forma predeterminada. El servidor procesará la solicitud del cliente. Una vez finalizado el servidor, cualquier actualización de la interfaz de usuario se transmite al cliente y se aplica al DOM.
El servidor mantiene un estado para cada cliente conectado. Este estado se conoce como circuito.
Se crea un circuito cuando iniciamos la aplicación en el navegador. Cada instancia de la aplicación en el navegador crea un nuevo circuito en el servidor. Esto significa que si abres la aplicación en dos pestañas diferentes del mismo navegador, se crearán dos circuitos en el servidor.
Cuando se cierra la aplicación, ya sea cerrando el navegador o navegando a una URL externa, el circuito y los recursos asociados se liberan inmediatamente.
Ventajas de utilizar Blazor Server
El servidor Blazor nos proporciona las siguientes ventajas.
- El tamaño de descarga de la aplicación es significativamente menor en comparación con la aplicación Blazor WebAssembly. Esto ayuda a cargar la aplicación más rápido.
- Una aplicación de servidor Blazor aprovecha al máximo las capacidades del servidor, como las API compatibles con .NET.
- Dado que la aplicación se ejecuta en el servidor, podemos aprovechar al máximo las herramientas .NET existentes, como la depuración.
- El código base de la aplicación no se comparte con los clientes.
¿Cuándo utilizar Blazor Server?
Se prefiere la aplicación del servidor Blazor en los siguientes escenarios:
- Cuando quieras que la aplicación se cargue rápidamente.
- Cuando desee que la aplicación acceda al servidor y a los recursos de la red.
- Dado que cada interacción del usuario implica un salto de red, se observa una alta latencia en las aplicaciones del servidor Blazor. Por lo tanto, opte por el servidor Blazor, donde la alta latencia no es un problema.
- Dado que todo el trabajo pesado lo realiza el servidor, se prefiere el servidor Blazor cuando los recursos del cliente son limitados.
- El servidor Blazor es adecuado para navegadores que no admiten WebAssembly.
Asamblea web Blazor
¿Qué es Blazor WebAssembly?
El modelo de hospedaje Blazor WebAssembly (WASM) permite que la aplicación Blazor se ejecute en el lado del cliente en el navegador en un tiempo de ejecución .NET basado en WebAssembly. Es el principal modelo de alojamiento de Blazor.
¿Cómo funciona Blazor WebAssembly?
El modelo de ejecución Blazor WASM se muestra en la siguiente imagen:
Cuando el usuario carga la aplicación, se descarga un pequeño archivo JavaScript (blazor.webassembly.js) en el navegador.
Este archivo maneja las dos operaciones siguientes:
- Descarga el tiempo de ejecución .NET junto con la aplicación Blazor y sus dependencias en el navegador.
- Inicializa el tiempo de ejecución de .NET para ejecutar la aplicación.
La ejecución de la aplicación ocurre directamente en el hilo de la interfaz de usuario del navegador. Las actualizaciones de la interfaz de usuario y el manejo de eventos también ocurren dentro del mismo proceso.
Se puede utilizar un servidor web o cualquier otro servicio que pueda ofrecer contenido estático a los clientes para implementar los activos de la aplicación como archivos estáticos.
Tipos de aplicación Blazor WebAssembly
Hay dos tipos de aplicación Blazor WASM:
- Independiente: cuando la aplicación Blazor WebAssembly se crea para su implementación sin una aplicación backend ASP.NET Core para entregar sus archivos, la aplicación se denomina aplicación Blazor WASM independiente.
- Alojada: cuando la aplicación se crea para su implementación con una aplicación backend para servir sus archivos, la aplicación se denomina aplicación Blazor WASM alojada. Una aplicación alojada proporciona una experiencia de desarrollo web completa con .NET. Nos permite compartir código entre las aplicaciones del cliente y del servidor, y admite la renderización previa y la integración con MVC y Razor Pages.
Ventajas de utilizar Blazor WebAssembly
Blazor WebAssembly nos proporciona las siguientes ventajas:
- No existe dependencia del lado del servidor una vez que la aplicación se descarga en el cliente. Esto garantiza que la aplicación siga funcionando incluso si el servidor se desconecta.
- El cliente hará el trabajo pesado. Por tanto, hay menos carga en el servidor.
- La aplicación aprovecha al máximo los recursos del cliente.
- Dado que no se requiere un servidor para alojar la aplicación, se admiten escenarios de implementación sin servidor.
¿Cuándo utilizar Blazor WebAssembly?
Se prefiere la aplicación Blazor WASM en los siguientes escenarios:
- Cuando queremos que la aplicación aproveche los recursos del cliente.
- Cuando se requiere que la aplicación se ejecute sin conexión si el cliente no puede conectarse a Internet.
- Cuando queremos alojar la aplicación como un sitio estático.
Blazor Híbrido
¿Qué es Blazor híbrido?
Blazor Hybrid nos permite crear aplicaciones cliente nativas usando .NET, HTML y CSS. Podemos utilizar los marcos de aplicaciones nativas .NET existentes, como .NET MAUI, WPF y Windows Forms, para crear una aplicación híbrida Blazor.
¿Cómo funciona Blazor Híbrido?
Una aplicación híbrida Blazor ejecuta los componentes de la afeitadora de forma nativa en el dispositivo. Los componentes Blazor se representan en un control de vista web integrado a través de un canal de interoperabilidad local. Los componentes se ejecutan directamente en la aplicación nativa y no en el navegador. Por lo tanto, WebAssembly no participa en una aplicación híbrida.
Una aplicación híbrida puede acceder a las capacidades de la plataforma nativa a través de las API de .NET. Al ser una aplicación nativa, una aplicación híbrida Blazor puede admitir funcionalidades que no están disponibles únicamente con la plataforma web. También podemos compartir y reutilizar los componentes existentes de la afeitadora desde un servidor Blazor o una aplicación Blazor WASM con una aplicación híbrida Blazor.
Ventajas de utilizar Blazor Hybrid
- Nos permite reutilizar componentes existentes del servidor Blazor y la aplicación Blazor WASM. Esto permite compartir código y reutilizarlo en plataformas móviles, de escritorio y web.
- La aplicación puede aprovechar las capacidades nativas del dispositivo.
¿Cuándo utilizar Blazor Híbrido?
Se prefiere la aplicación Blazor Hybrid en los siguientes escenarios:
- Cuando queremos crear una aplicación nativa utilizando las API de .NET.
- Cuando queremos aprovechar las capacidades del cliente nativo.
- Cuando se requiere que la aplicación se ejecute sin conexión.
- Cuando queremos descargar el procesamiento de datos de la aplicación al cliente
Componentes Blazor
¿Qué son los componentes Blazor?
Un componente Blazor se define como parte de la interfaz de usuario, como la barra de navegación, los botones, el formulario, etc. Los componentes Blazor se crean como archivos de componentes Razor con la extensión ".razor".
Los componentes son reutilizables y se pueden compartir en varios proyectos. Un componente Blazor también se conoce como componente Razor.
Razor es una sintaxis de marcado para combinar código HTML y C#.
El nombre de un componente Blazor debe comenzar con un carácter en mayúscula.
por ejemplo, el nombre LoginForm.razor es un nombre de componente válido. Mientras que el nombre loginForm.razor es un nombre de componente no válido.
Mire el código del componente de ejemplo que se muestra a continuación:
@página "/contador"
<PageTitle>Contador</PageTitle>
<h1>Contador</h1>
<p role="status" >Recuento actual: @currentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Haz clic en mí</button>
@código {
privado int currentCount = 0;
IncrementCount vacío privado()
{
cuentaactual++;
}
}
La directiva @page se utiliza para especificar la ruta del componente. La directiva @code se utiliza para especificar el código C# para el componente. El método IncrementCount se invocará en el evento de clic del botón.
También podemos usar directivas @page múltiples, pero distintas, para un solo componente. No podemos marcar la misma ruta para dos componentes diferentes. Hacerlo resultará en un error de tiempo de ejecución.
Clase base de componente
Podemos crear una clase base para que el componente separe la lógica HTML y C#. La clase base debe derivar de la clase ComponentBase. Podemos usar la directiva @inherits para heredar una clase base en un componente.
Hemos creado una clase base Welcome.razor.cs como se muestra a continuación:
utilizando Microsoft.AspNetCore.Components;
espacio de nombres BlazorTutorial.Client.Pages;
clase pública Base de bienvenida: Base de componentes { cadena pública Mensaje de bienvenida {obtener; colocar; } = "Bienvenido al tutorial Blazor."; }
Hemos creado un componente de afeitar Welcome.razor como se muestra a continuación:
@página "/bienvenido"
@inherits BienvenidoBase
<h1>@Mensaje de bienvenida</h1>
Estamos usando la directiva @inherits para heredar la clase base.
Parámetros de los componentes
Los parámetros de los componentes se utilizan para pasar datos del componente principal al secundario.
Entendamos esto con la ayuda de un ejemplo.
Cree un componente Child.razor como se muestra a continuación:
<h3>Componente secundario</h3>
<p>La suma del número es: @(num1 + num2)</p>
@código {
[Parámetro]
public int num1 {obtener; colocar; }
[Parámetro]
public int num2 {obtener; colocar; }
}
Los parámetros del componente están anotados con el atributo [Parámetro]. Este componente aceptará dos parámetros de tipo entero y mostrará la suma de ambos números.
Cree otro componente Parent.razor como se muestra a continuación:
@página "/padre"
<h3>Componente principal</h3>
<Niño num1="5" num2="10"><Niño>
Hemos invocado el componente secundario dentro del componente principal y le hemos pasado ambos parámetros.
También podemos asignar la propiedad C# al valor del parámetro usando el símbolo “@”.
Mire el ejemplo que se muestra a continuación:
@página "/padre"
<h3>Componente principal</h3>
<Niño num1="@number1" num2="@number2"><Niño>
@código {
int número1 = 5;
int número2 = 10;
}
Un parámetro se puede marcar como requerido usando el atributo [EditorRequired].
Mire el ejemplo que se muestra a continuación:
<h3>Componente secundario</h3>
<p>La suma del número es: @(num1 + num2)<p>
@código {
[Parámetro]
[Editor requerido]
public int num1 {obtener; colocar; }
[Parámetro]
[Editor requerido]
public int num2 {obtener; colocar; }
}
Debemos usar el atributo [Parámetro] mientras usamos el atributo [EditorRequired].
Si no proporcionamos los parámetros requeridos al invocar el componente, generará una advertencia en tiempo de compilación.
También podemos proporcionar valores predeterminados a los parámetros del componente.
Mire el ejemplo que se muestra a continuación:
@página "/bienvenido"
<h1>Mensaje de bienvenida</h1>
@código {
[Parámetro]
cadena pública Mensaje de bienvenida { get; colocar; } = "Bienvenido";
}
Ciclo de vida de los componentes Razor
Los componentes Razor pasan por una serie de eventos de ciclo de vida desde su creación hasta su eliminación. Tiene métodos tanto sincrónicos como asincrónicos. El marco Blazor nos permite anular los métodos del ciclo de vida para realizar operaciones adicionales en los componentes.
Establecer parámetrosAsync
Este método se llamará antes de que se establezcan los parámetros. Establecerá los parámetros proporcionados por el componente principal o desde la ruta del componente. Debemos llamar al método base.SetParametersAsync() para establecer el valor de los parámetros del componente. De lo contrario, necesitamos escribir nuestro código personalizado para manipular los parámetros.
OnInitialized
Este método se llamará antes de que se establezcan los parámetros. Se invocará cuando el componente esté listo para iniciarse después de recibir los parámetros iniciales de su padre.
La versión asincrónica se llama OnInitializedAsync. Anule OnInitializedAsync si desea realizar una operación asincrónica y desea que el componente se actualice cuando se complete esa operación.
OnParametersSet
Este método se llamará después de que se establezcan los parámetros. Se invocará cuando el componente haya recibido parámetros de su padre y los valores entrantes se hayan asignado a las propiedades. Este método se ejecutará cada vez que se actualicen los parámetros. La versión asincrónica se llama OnParametersSetAsync.
OnAfterRender
Este método se llamará después de que un componente haya terminado de renderizarse, es decir, cuando el HTML ya se muestre. Este método se puede utilizar para realizar cualquier paso adicional necesario para la inicialización del componente, como activar cualquier biblioteca JavaScript de terceros que utilice los elementos DOM renderizados. Este método se ejecuta cada vez que se renderiza el componente. La versión asincrónica se conoce como OnAfterRenderAsync.
StateHasChanged
Este método notificará al componente que su estado ha cambiado y luego volverá a renderizar el componente. Durante un EventCallback, este método se llamará automáticamente para volver a representar el componente principal.
Invocar este método nos permitirá renderizar el componente en cualquier momento. Sin embargo, demasiadas llamadas a StateHasChanged pueden agregar costos de procesamiento innecesarios a la aplicación.
Entendamos esto con la ayuda de un ejemplo.
Hemos creado una clase base Lifecycle.razor.cs como se muestra a continuación:
utilizando Microsoft.AspNetCore.Components;
espacio de nombres BlazorTutorial.Client.Pages;
clase pública LifecycleBase: ComponentBase { anulación pública async Task SetParametersAsync (parámetros ParameterView){ Console.WriteLine ("SetParametersAsync-start"); await base.SetParametersAsync(parámetros); Console.WriteLine("SetParametersAsync-end"); }
anulación protegida void OnInitialized() { Console.WriteLine("OnInitialized-start"); base.OnInitialized(); Console.WriteLine("OnInitialized-end"); }
anulación protegida tarea asíncrona OnInitializedAsync() { Console.WriteLine("OnInitializedAsync-start"); espere base.OnInitializedAsync(); Console.WriteLine("OnInitializedAsync-end"); }
anulación protegida void OnParametersSet() { Console.WriteLine("OnParametersSet-start"); base.OnParametersSet(); Console.WriteLine("OnParametersSet-end"); }
anulación protegida tarea asíncrona OnParametersSetAsync() {Console.WriteLine("OnParametersSetAsync-start"); await base.OnParametersSetAsync(); Console.WriteLine("OnParametersSetAsync-end"); }
anulación protegida void OnAfterRender(bool firstRender) { Console.WriteLine("OnAfterRender({0})-start", firstRender); base.OnAfterRender(primerRender); Console.WriteLine("OnAfterRender({0})-end", firstRender); }
anulación protegida tarea asíncrona OnAfterRenderAsync(bool firstRender) { Console.WriteLine("OnAfterRenderAsync({0})-start", firstRender); await base.OnAfterRenderAsync(firstRender); Console.WriteLine("OnAfterRenderAsync({0})-end", firstRender); } }
Hemos creado un componente de afeitar Lifecycle.razor como se muestra a continuación:
@página "/ciclo de vida"
@inherits BienvenidoBase
<h1> Ejemplo de ciclo de vida del componente Blazor </h1>
Cuando ejecutamos la aplicación y navegamos hasta el componente del ciclo de vida, podemos ver el resultado en la consola del navegador como se muestra a continuación:
Este resultado muestra la secuencia de ejecución de los métodos del ciclo de vida de un componente Razor.
Valores y parámetros en cascada Blazor
Los valores y parámetros en cascada nos permiten pasar datos de un componente a todos sus componentes descendientes. Un componente puede proporcionar un valor en cascada utilizando el componente <CascadingValue>.
Para utilizar los valores en cascada proporcionados por el componente principal, un componente secundario puede declarar parámetros en cascada utilizando el atributo [CascadingParameter].
Los valores en cascada están vinculados a parámetros en cascada por tipo de datos. Si queremos poner en cascada varios valores del mismo tipo, podemos proporcionar un nombre único a cada atributo [CascadingParameter].
Entendamos esto con la ayuda de un ejemplo.
Cree un componente Child.razor como se muestra a continuación:
<h3>Componente secundario</h3>
<p>La suma del número es: @(num1 + num2)</p>
@código {
[CascadingParameter(Nombre = "PrimerNúmero")]
public int num1 {obtener; colocar; }
[CascadingParameter(Nombre = "SegundoNúmero")]
public int num2 {obtener; colocar; }
}
Cree un componente Parent.razor como se muestra a continuación:
@página "/padre"
<h3>Componente principal</h3>
<Valor en cascada="@número1" Nombre="PrimerNúmero" >
<Valor en cascada="@número2" Nombre="SegundoNúmero" >
<Niño></Niño>
</CascadingValue>
</CascadingValue>
@código {
int número1 = 5;
int número2 = 10;
}
Llamamos al componente secundario y le pasamos los valores en cascada. El componente secundario vinculará los valores de los parámetros utilizando la propiedad Nombre.
Pasar datos a través de una jerarquía de componentes
Podemos utilizar los parámetros en cascada para pasar datos a través de la jerarquía de componentes.
Entendamos esto con la ayuda de un ejemplo.
Cree un componente GrandChild.razor como se muestra a continuación:
<h3>Componente nieto nieto</h3>
<p>El producto del número es: @(num1 * num2)</p>
@código {
[CascadingParameter(Nombre = "PrimerNúmero")]
public int num1 {obtener; colocar; }
[CascadingParameter(Nombre = "SegundoNúmero")]
public int num2 {obtener; colocar; }
}
Cree un componente Child.razor como se muestra a continuación:
<h3>Componente secundario</h3>
<p>La suma del número es: @(num1 + num2)</p>
<Nieto></Nieto>
@código {
[Parámetro]
public int num1 {obtener; colocar; }
[Parámetro]
public int num2 {obtener; colocar; }
}
@página "/padre"
<h3>Componente principal</h3>
<Valor en cascada="10" Nombre="PrimerNúmero" >
<Valor en cascada="5" Nombre="SegundoNúmero" >
<Niño></Niño>
</CascadingValue>
</CascadingValue>
@código {
int número1 = 5;
int número2 = 10;
}
Hemos pasado los valores en cascada del componente principal al componente nieto. Tenga en cuenta que el nombre de los parámetros en cascada es el mismo en los componentes Child y GrandChild.
Tras la ejecución, puede ver un resultado como se muestra a continuación:
Enlace de datos Blazor
Enlace de datos unidireccional
Nos permite vincular el valor de una propiedad a elementos HTML DOM, pero no al revés. Para vincular una propiedad o un campo a una etiqueta HTML, debemos pasar el nombre de la propiedad, con el prefijo @.
Mire el ejemplo que se muestra a continuación:
@página "/enlace de datos"
<h3>Enlace de datos unidireccional</h3>
<p>@TextoDeMuestra</p>
@código {
string SampleText = "Este es un texto de muestra que muestra el enlace de datos unidireccional";
}
El campo C# SampleText está vinculado al DOM HTML mediante el símbolo @.
Enlace de datos bidireccional
Nos permite vincular el valor de una propiedad o un campo a elementos HTML DOM, y viceversa. Podemos lograr un enlace de datos bidireccional utilizando el atributo @bind.
Podemos vincular una propiedad de C# en eventos DOM usando el atributo @bind:event="{EVENT}" en los elementos HTML, donde {EVENT} es un marcador de posición para los eventos DOM.
Mire el ejemplo que se muestra a continuación:
@página "/enlace de datos"
<h3>Enlace de datos bidireccional</h3>
<div>
<span>Ingrese su nombre: </span>
<tipo de entrada="texto" @bind="Nombre" @bind:event="oninput" />
</div>
<br/>
<p>Tu nombre es: @Nombre</p>
@código {
Nombre de cadena {obtener; colocar; }
}
El valor del campo de entrada está vinculado a la propiedad Nombre. El enlace de datos se producirá cuando se active el evento oninput del campo de entrada, es decir, cuando cambie el valor del cuadro de texto.
NOTE:
El enlace de atributos distingue entre mayúsculas y minúsculas. Esto significa que @bind, @bind:event es válido, mientras que @Bind, @Bind:EVENT y otras sintaxis que utilizan caracteres en mayúsculas no son válidas.
Vincular múltiples opciones usando el elemento <select>
Podemos vincular los valores de una selección múltiple a una propiedad C# de tipo matriz.
Mire el ejemplo que se muestra a continuación:
@página "/enlace de datos"
<p>
<etiqueta>
Seleccione uno o más días:
<seleccione @onchange="DíasSeleccionadosCambiados" múltiples >
<option value="monday">Lunes</option>
<option value="martes">Martes</option>
<option value="miércoles">miércoles</option>
<option value="jueves">jueves</option>
<option value="viernes">viernes</option>
</seleccionar>
</etiqueta>
</p>
<p>
Días seleccionados: @string.Join(", ", SelectedDays)
</p>
@código {
cadena pública [] Días seleccionados { get; colocar; } = nueva cadena[] { };
anular los días seleccionados cambiados (ChangeEventArgs e)
{
si (e.Value no es nulo) {
Días seleccionados = (cadena []) e.Value;
}
}
}
Los valores seleccionados están vinculados a una matriz de cadenas utilizando el evento @onchange del elemento <select>.
Vincular a una cadena formateada
El enlace de datos funciona con una cadena formateada usando la sintaxis @bind:format="{FORMAT STRING}"
El enlace de datos formateado es compatible con los siguientes tipos de .NET:
- Sistema.FechaHora
- Sistema.DateTimeOffset
Mire el ejemplo que se muestra a continuación:
@página "/enlace de datos"
<h3>Cadena formateada</h3>
<div>
<span>La fecha de la muestra es: </span>
<entrada @bind="Fecha de muestra" @bind:format="dd-MM-aaaa" />
</div>
@código {
FechaHora FechaMuestra { get; colocar; } = nueva FechaHora(2023, 1, 14);
}
La fecha se mostrará en el formato especificado utilizando el atributo @bind:format.
Podemos especificar un formato de enlace personalizado utilizando los descriptores de acceso get y set.
Mire el ejemplo que se muestra a continuación:
@página "/enlace de datos"
<entrada @bind="ValorSalario" />
<h3>Cadena formateada</h3>
<p>
<código>valor decimal</código>: @salario
</p>
@código {
salario decimal = 123456;
cadena ValorSalario {
obtener => salario.ToString("0.000");
colocar {
if (Decimal.TryParse(valor, número de var de salida)) {
salario = Math.Round(número, 3);
}
}
}
}
La propiedad de cadena SalaryValue está vinculada hasta tres decimales con el elemento de entrada.
Vinculación con parámetros de componentes
Podemos vincular la propiedad de un componente secundario a una propiedad de su componente principal. Dado que el enlace de datos ocurre en múltiples niveles, este escenario se conoce como enlace encadenado.
Podemos usar la sintaxis @bind-{PROPERTY}, donde {PROPERTY} es un marcador de posición para la propiedad a vincular. Debemos proporcionar un controlador de eventos y un valor para admitir la actualización de la propiedad en el componente principal desde el componente secundario.
Entendamos esto con la ayuda de un ejemplo.
Cree un componente Child.razor como se muestra a continuación:
<h3>Componente secundario</h3>
<p>Mensaje secundario: @Message</p>
<button @onclick="UpdateMessageFromChild">Actualizar mensaje del niño</button>
@código {
[Parámetro]
Mensaje de cadena pública { get; colocar; }
[Parámetro]
public EventCallback <cadena> MessageChanged { get; colocar; }
Tarea asíncrona privada UpdateMessageFromChild() {
await MessageChanged.InvokeAsync("Mensaje del componente secundario");
}
}
Hemos declarado un parámetro de componente de tipo cadena y un EventCallback del mismo tipo que el parámetro del componente.
El nombre de EventCallback debe seguir la sintaxis {NOMBRE DEL PARÁMETRO}Cambiado, donde {NOMBRE DEL PARÁMETRO} es un marcador de posición para el nombre del parámetro del componente. El uso de cualquier otro formato de nomenclatura provocará un error de tiempo de ejecución.
En el ejemplo que se muestra arriba, el parámetro del componente se denomina Mensaje y EventCallback se denomina MessageChanged.
Cree un componente Parent.razor como se muestra a continuación:
@página "/padre"
<h3>Componente principal</h3>
<Niño @bind-Message="MessageFromParent"></Niño>
<button @onclick="UpdateMessageFromChild">Actualizar mensaje del niño</button>
@código {
string MesssageFromParent = "Mensaje del componente principal";
}
La propiedad C# MesssageFromParent está vinculada al parámetro Mensaje del componente secundario. El parámetro Mensaje del componente secundario se puede vincular porque tiene un evento MessageChanged complementario del mismo tipo que el del parámetro Mensaje.
Tras la ejecución, puede ver un resultado como se muestra a continuación:
Tan pronto como haga clic en el botón, el mensaje se actualizará como se muestra en la imagen a continuación:
Manejo de eventos Blazor
Agregue un atributo HTML con el nombre @on{EVENT} y tenga un valor de tipo delegado. El valor de este atributo lo trata el componente Blazor como un controlador de eventos.
Algunos de los controladores de eventos admitidos por Blazor son @onclick, @onchange, @onselect, @onfocus, @onkeyup, etc.
Ejemplo:
<button @onclick="ButtonClicked">Haz clic en mí</button>
@código {
void BotónClic() {
Console.WriteLine("botón hecho clic");
}
}
El método ButtonClicked se invocará cuando hagamos clic en el botón.
Manejo de eventos asíncronos
Mire el ejemplo que se muestra a continuación:
<button @onclick="ButtonClicked">Haz clic en mí</button>
@código {
Botón de tarea asíncrono hecho clic () {
await Task.Delay(1000);
Console.WriteLine("botón hecho clic");
}
}
El método ButtonClicked se invocará de forma asincrónica cuando se haga clic en el botón.
Usar argumentos de eventos
Mire el ejemplo que se muestra a continuación:
<select class="form-control col-md-4" @onchange="SelectGender" />
<option value="">-- Seleccione Género --</option>
<option value="Hombre">Hombre</option>
<option value="Famale">Famale</option>
</seleccionar>
@código {
cadena protegida Género { get; colocar; }
vacío protegido SelectGender (ChangeEventArgs e) {
Género = e.Value.ToString();
}
}
Hemos vinculado el método SelectGender al evento onchange del elemento seleccionado.
Especificar un argumento de evento en la definición del método de evento es opcional. Es obligatorio sólo cuando se utiliza el argumento del evento en el método.
Usar expresiones Lambda para el manejo de eventos
Podemos usar una expresión lambda para crear una función anónima para el atributo del evento.
Mire el ejemplo que se muestra a continuación:
@for (int i = 1; i < 4; i++) {
int textboxNumber = i;
<p>
<entrada> @onfocus="@(() => FocusTextbox(textboxNumber))" />
</p>
}
@código {
cadena protegida Género { get; colocar; }
cuadro de texto vacío protegido FocusText (int número de cuadro de texto) {
Console.WriteLine($"Ha seleccionado el número de cuadro de texto {textboxNumber}");
}
}
Hemos creado tres controles de cuadro de texto usando un bucle for. Hemos utilizado una expresión lambda para invocar el método FocusTextbox en el evento onfocus de cada cuadro de texto.
EventCallback
EventCallback se puede utilizar para exponer eventos en varios componentes. Esto ayuda a invocar el método de un componente principal cuando ocurre un evento en un componente secundario.
Podemos escribir fuertemente un EventCallback especificando un parámetro de evento usando la sintaxis EventCallback<TValue>.
Por ejemplo, EventCallback<MouseEventArgs>
Entendamos EventCallback con la ayuda de un ejemplo.
Cree un componente Child.razor como se muestra a continuación:
<h3>Componente secundario</h3>
<botón class="btn btn-primary" @onclick="ChildClick">
Invocar el método del componente principal
</botón>
@código {
[Parámetro]
público EventCallback ChildClick { get; colocar; }
}
Cree otro componente Parent.razor como se muestra a continuación:
<h3>Componente principal</h3>
<Niño ChildClick="ChildClickHandler"> </Niño>
<p><strong> @mensaje </strong></p>
@código {
mensaje de cadena {obtener; colocar; }
vacío ChildClickHandler() {
mensaje = "Se ha producido un evento secundario";
}
}
Hemos creado un parámetro EventCallback en el componente secundario. El controlador de eventos onclick del botón está configurado para recibir un delegado EventCallback del ParentComponent.
ParentComponent establece el EventCallback, ChildClick del componente secundario en su método ChildClickHandler.
Cuando hacemos clic en el botón del componente secundario, invocará el método ChildClickHandler del componente principal. El mensaje de propiedad de cadena se actualiza y se muestra en ParentComponent.
Prevenir acciones predeterminadas
Podemos usar el atributo de directiva @on{DOM EVENT}:preventDefault para evitar la acción predeterminada para un evento. Este atributo acepta un valor booleano como argumento. Si no especificamos ningún argumento, se considerará el valor predeterminado de verdadero.
Mire el ejemplo que se muestra a continuación:
<valor de entrada="@nombre" @onkeydown="KeyDownHandler" @onkeydown:preventDefault />
@código {
nombre de cadena privada {obtener; colocar; }
KeyDownHandler vacío privado (KeyboardEventArgs e) {
// hacer algo
}
}
El atributo booleano se puede vincular a una propiedad y, por lo tanto, podemos controlar la propagación del evento según los requisitos del usuario.
Mire el ejemplo que se muestra a continuación:
<input @onkeydown="KeyDownHandler" @onkeydown:preventDefault="shouldPreventDefault" />
@código {
bool privado deberíaPreventDefault = verdadero;
}
Detener la propagación de eventos
A veces, los elementos HTML propagan eventos a sus elementos principales.
Blazor nos permite usar el atributo de directiva @on{DOM EVENT}:stopPropagation para detener la propagación de eventos. Este atributo acepta un valor booleano como argumento. Si no especificamos ningún argumento, se considerará el valor predeterminado de verdadero.
Mire el ejemplo que se muestra a continuación:
<botón @onclick:stopPropagation>Hacer clic</button>
El atributo booleano se puede vincular a una propiedad y, por lo tanto, podemos controlar la propagación del evento según los requisitos del usuario.
<button @onclick:stopPropagation="shouldStopPropagation">Hacer clic</button>
@código {
bool privado deberíaStopPropagation = verdadero;
}
Enrutamiento y navegación
El componente Router, utilizado en el archivo App.razor, permite el enrutamiento a los componentes de una aplicación Blazor.
Cuando creamos una aplicación Blazor, el archivo App.razor contendrá el código como se muestra a continuación.
<Enrutador AppAssembly="@typeof(App).Assembly >
<Contexto encontrado="rutaDatos" >
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
<FocusOnNavigate RouteData="@routeData" Selector="h1" />
</Encontrado>
<No encontrado>
<PageTitle>No encontrado</PageTitle>
<LayoutView Diseño="@typeof(MainLayout)">
<p role="alert"> Lo sentimos, no hay nada en esta dirección.</p>
</LayoutView>
</NotFound>
</enrutador>
El componente Enrutador se utiliza para proporcionar datos de ruta correspondientes al estado de navegación actual. El componente FocusOnNavigate se utiliza para establecer el foco en un elemento que coincide con un selector CSS cuando el usuario navega de un componente a otro. Esto nos permite crear un mecanismo de enrutamiento accesible que sea compatible con lectores de pantalla.
La propiedad NotFound se utiliza para mostrar contenido personalizado cuando no se encuentran datos en la ruta solicitada.
Podemos usar la directiva @page para definir la ruta para un componente Razor. También podemos usar directivas @page múltiples pero distintas para un solo componente.
Mire el ejemplo que se muestra a continuación:
@página "/ruta1"
@página "/inicio/ruta1"
<h1>Se puede acceder a este componente a través de múltiples rutas.</h1>
No podemos marcar la misma ruta para dos componentes diferentes. Hacerlo resultará en un error de tiempo de ejecución.
Parámetros de ruta
Podemos definir parámetros de ruta que se pueden usar para completar los parámetros del componente con el mismo nombre. Una ruta puede tener múltiples parámetros.
Mire el ejemplo que se muestra a continuación:
@page "/home/{Nombre}/{Mensaje}"
<h1>Hola @Nombre</h1>
<h3>@Mensaje</h3>
@código {
[Parámetro]
Nombre de cadena pública {obtener; colocar; }
[Parámetro]
Mensaje de cadena pública { get; colocar; }
}
La propiedad del parámetro de ruta del componente debe definirse como pública. El uso de cualquier otro modificador de acceso generará un error en tiempo de compilación.
Los nombres de los parámetros de ruta no distinguen entre mayúsculas y minúsculas, lo que significa que podemos usar los parámetros de ruta como se muestra a continuación:
@página "/home/{nombre}/{mensaje}"
<h1>Hola @NOMBRE</h1>
<h3>@MENSAJE</h3>
@código {
[Parámetro]
NOMBRE de cadena pública {obtener; colocar; }
[Parámetro]
MENSAJE de cadena pública {obtener; colocar; }
}
Blazor también admite parámetros de ruta opcionales. Para marcar un parámetro de ruta como opcional, añádale el sufijo ? símbolo.
Mire el ejemplo que se muestra a continuación:
@page "/home/{nombre}/{mensaje?}"
<h1>Hola @Nombre</h1>
<h3>@Mensaje</h3>
@código {
[Parámetro]
Nombre de cadena pública {obtener; colocar; }
[Parámetro]
Mensaje de cadena pública { get; colocar; }
}
Podemos tener más de un parámetro opcional.
La siguiente ruta es válida.
@page "/home/{nombre}/{mensaje?}/{texto?}"
Los parámetros no opcionales no pueden aparecer después de los parámetros opcionales. Si agrega cualquier parámetro no opcional después de un parámetro opcional, obtendrá un error de tiempo de ejecución.
La siguiente ruta no es válida.
@page "/home/{nombre?}/{mensaje}"
Restricciones de ruta
Podemos usar las restricciones de ruta para imponer la coincidencia de tipos en la ruta.
Mire el ejemplo que se muestra a continuación:
@page "/home/{nombre}/{userID:int}/{isAdmin:bool}"
<h1>Hola @Nombre</h1>
<h3>ID de usuario: @ID de usuario</h3>
<h3>isAdmin: @isAdmin</h3>
@código {
[Parámetro]
Nombre de cadena pública {obtener; colocar; }
[Parámetro]
public int ID de usuario {obtener; colocar; }
[Parámetro]
público booleano isAdmin { get; colocar; }
}
La ruta para este componente coincidirá si se cumplen los siguientes criterios:
- La ruta debe tener un valor para el parámetro de nombre.
- La ruta debe tener un valor para el parámetro ID de usuario y debe ser de tipo int.
- La ruta debe tener un valor para el parámetro isAdmin y debe ser de tipo bool.
Una ruta de ejemplo para coincidir con este patrón puede ser: “/home/John/1234/true”
También podemos usar restricciones de ruta con parámetros opcionales.
p ej.:
@page "/home/{nombre}/{userID:int}/{isAdmin:bool?}"
NavigationManager
Podemos usar la clase NavigationManager para manejar la navegación a través del código C#. Esta clase proporciona un método NavigateTo, que acepta la ruta del componente como parámetro y redirige al usuario de un componente a otro.
Entendamos esto con la ayuda de un ejemplo.
Hemos creado una clase base Routing.razor.cs como se muestra a continuación:
utilizando Microsoft.AspNetCore.Components;
espacio de nombres BlazorWasmDemo.Client.Pages;
clase pública RoutingBase: ComponentBase { [Inyectar] public NavigationManager NavigationManager { get; colocar; }
[Parámetro] nombre de cadena pública { get; colocar; }
void protegido NavigateAway() { NavigationManager.NavigateTo("padre/1234"); } }
Agregaremos el siguiente código en el componente Routing.razor.
@página "/home/{nombre}"
@hereda la base de enrutamiento
<h1>Hola @Nombre</h1>
<button @onclick="NavigateAway" >Navegar lejos</button>
Invocaremos el método NavigateAway con solo hacer clic en un botón. Redireccionará al usuario a la ruta “/parent/1234”.
El método NavigateTo acepta un parámetro booleano opcional, forceLoad. Si pasamos el valor verdadero para este parámetro, el navegador recargará la nueva página desde el servidor.
Parámetros de ruta generales
Se puede utilizar un parámetro de ruta general para manejar varias rutas cuando los parámetros de ruta no están definidos explícitamente.
Mire el componente de ejemplo que se muestra a continuación:
@página "/home/{*routeParams}"
@código {
[Parámetro]
cadena pública? Parámetros de ruta { get; colocar; }
}
Para este componente, las siguientes rutas son válidas:
- /inicio/Juan
- /inicio/123
- /home/John/123/345/USA/true
Un parámetro de ruta general debe seguir los siguientes criterios:
- Debería tener un parámetro de componente correspondiente con el mismo nombre. El nombre no distingue entre mayúsculas y minúsculas.
- Debería ser del tipo cadena. No podemos utilizar restricciones de ruta sobre ellos.
- Debe estar presente al final de la URL.
Componente NavLink
Podemos utilizar el componente NavLink en lugar del atributo <a> en HTML al crear enlaces de navegación. Alterna una clase CSS activa, en función de si la URL actual coincide con la propiedad href. Esto ayuda al usuario a comprender qué páginas están activas entre todos los enlaces de navegación disponibles.
p ej.:
<NavLink class="nav-link" href="" Match="NavLinkMatch.All" >
<span class="oi oi-home" aria-hidden="true"></span> Inicio
</NavEnlace>
El atributo Match del componente NavLink puede tener dos valores posibles:
- NavLinkMatch.All: NavLink debe estar activo solo si coincide con la URL actual completa
- NavLinkMatch.Prefix: NavLink debe estar activo solo si coincide con algún prefijo de la URL actual. Este es el valor predeterminado.
cadenas de consulta
Podemos usar el atributo [SupplyParameterFromQuery] junto con el atributo [Parameter] para especificar que el parámetro del componente se puede proporcionar mediante una cadena de consulta desde la ruta.
@página "/película"
<p>@Nombre</p>
<p>@Género</p>
@código {
[Parámetro]
[Parámetro de suministro de consulta]
cadena pública? Nombre {obtener; colocar; }
[Parámetro]
[Parámetro de suministro de consulta]
cadena pública? Género { obtener; colocar; }
}
Una ruta válida para este componente puede ser “/movie?name=avatar&genre=science%20fiction”. Podemos especificar el nombre del parámetro de consulta utilizando la propiedad Nombre.
p ej.:
[Parámetro]
[SupplyParameterFromQuery(Nombre="Categoría")]
cadena pública? Género { obtener; colocar; }
Una ruta válida, en este caso, será “/movie?name=avatar&category =science%20fiction”
Un parámetro de consulta para el componente admite los siguientes tipos de datos:
- booleano
- Fecha y hora
- decimal
- doble
- flotar
- guía
- En t
- largo
- cadena
Podemos utilizar el método GetUriWithQueryParameter de la clase NavigationManager para agregar, actualizar o eliminar uno o más parámetros de consulta de la URL actual.
La sintaxis de este método es GetUriWithQueryParameter("{NOMBRE}", {VALOR}), donde {NOMBRE} es un marcador de posición para el nombre del parámetro de consulta y {VALOR} es un marcador de posición para el valor del parámetro de consulta. El método devolverá un valor de cadena.
Si el parámetro de consulta ya existe en el URI actual, este método actualizará el valor. Si el parámetro de consulta no existe en el URI actual, este método agregará el nuevo parámetro con el valor especificado.
p ej.:
@página "/película"
@inject NavigationManager Navegación
<p>@Nombre</p>
<p>@Género</p>
<button @onclick="UpdateCurrentURI">Actualizar URI</button>
<p>NuevoURI: @NuevoURI</p>
<button @onclick="NavigateToNewURI">Ir a nueva URI</button>
@código {
cadena NuevoURI {obtener; colocar; }
[Parámetro]
[Parámetro de suministro de consulta]
cadena pública? Nombre {obtener; colocar; }
[Parámetro]
[SupplyParameterFromQuery(Nombre = "Categoría")]
cadena pública? Género { obtener; colocar; }
vacío UpdateCurrentURI() {
NewURI = Navigation.GetUriWithQueryParameter("nombre", "Top Gun");
}
vacío NavigateToNewURI() {
Navegación.NavigateTo(NewURI);
}
}
El valor del parámetro de consulta, "nombre", se actualizará cuando hagamos clic en el botón.
Si queremos agregar un nuevo parámetro de consulta al URI, podemos actualizar el código como se muestra a continuación:
NewURI = Navigation.GetUriWithQueryParameter("idioma", "inglés");
Si queremos eliminar un parámetro de consulta existente del URI, podemos establecer el valor en nulo como se muestra a continuación:
NewURI = Navigation.GetUriWithQueryParameter("nombre", (cadena?)null);
Podemos usar el método GetUriWithQueryParameters para agregar, actualizar y eliminar múltiples parámetros de un URI simultáneamente.
Mire el ejemplo que se muestra a continuación:
NewURI = Navigation.GetUriWithQueryParameters(nuevo diccionario<cadena, objeto?>
{
["nombre"] = "Top Gun",
["categoría"] = "Acción",
["idioma"] = "inglés",
});
Esto actualizará los parámetros de consulta existentes, nombre y categoría y agregará un nuevo parámetro de consulta, idioma con el valor establecido en inglés.
diseños Blazor
Un diseño es un componente Blazor que contiene las funciones de la interfaz de usuario que son comunes en varios componentes, como el menú de navegación, el encabezado, el pie de página, etc. El diseño predeterminado de la aplicación se define en el componente Router dentro del archivo App.razor.
Podemos usar diseños solo para los componentes enrutables Razor que tengan la directiva @page. El diseño predeterminado de la aplicación se define en el componente Router dentro del archivo App.razor.
Podemos usar la directiva @layout para especificar el diseño de un componente enrutable que tenga la directiva @page. La especificación del diseño directamente en un componente anula el diseño predeterminado de la aplicación establecido en el componente Enrutador.
Mire el ejemplo que se muestra a continuación:
@layoutDiseño personalizado
@page "/diseño-demostración"
<h1>Demostración de diseño personalizado.</h1>
Blazor admite el anidamiento de diseños. Un componente puede hacer referencia a un diseño, que a su vez hará referencia a otro diseño. Esto puede ayudar a crear una estructura de menú de varios niveles.
Crear un componente de diseño personalizado
Para que un componente actúe como componente de diseño, debe cumplir los dos criterios siguientes:
- Debería heredarse de la clase LayoutComponentBase. Esta clase define una propiedad Cuerpo, que se utiliza para representar el contenido dentro del diseño.
- Debe definir una ubicación para especificar dónde se debe representar el contenido del cuerpo. Esto se hace utilizando la sintaxis Razor @Body.
Mire el ejemplo que se muestra a continuación:
@inherits LayoutComponentBase
<encabezado>
<h1>Bienvenido al tutorial Blazor </h1>
</encabezado>
@Cuerpo
<pie de página>
<h1>Todos los derechos reservados</h1>
</pie de página>
Inyección de dependencia
La inyección de dependencia (DI) es un patrón de diseño de software que nos ayuda a lograr la inversión de control (IoC) entre clases y sus dependencias.
Podemos inyectar los servicios registrados en el marco directamente en los componentes Blazor. Los servicios personalizados deben registrarse en la aplicación Blazor para que estén disponibles a través de DI.
Vida útil del servicio
Los servicios Blazor se pueden configurar con las siguientes tres duraciones:
- Singleton: crea una instancia única de un servicio que se comparte entre todos los componentes.
- Transitorio: crea una nueva instancia de un servicio cada vez que un componente solicita el servicio.
- Alcance: esto crea una instancia de servicio por solicitud web.
- Las aplicaciones Blazor WebAssembly no admiten la duración del alcance. Un servicio registrado con ámbito se comporta como un servicio Singleton para aplicaciones Blazor WebAssembly.
- Las aplicaciones Blazor Server admiten la duración del alcance en las solicitudes HTTP, pero no en los mensajes de conexión de SignalR entre los componentes que se cargan en el lado del cliente.
Servicios Blazor predeterminados
Los servicios que se muestran en la siguiente tabla se usan con frecuencia en las aplicaciones Blazor.
Servicio | Blazor Wasm de por vida | Vida útil del servidor Blazor | Descripción |
---|---|---|---|
HttpClient | Alcance | Alcance | Proporciona métodos para manejar solicitudes y respuestas HTTP desde una URL de recurso. |
IJSRuntime | único | Alcance | Representa una instancia de un tiempo de ejecución de JavaScript donde se envían las llamadas de JavaScript. |
NavigationManager | único | Alcance | Proporciona clases de ayuda para consultar y gestionar la navegación URI. |
Agregar servicios a una aplicación Blazor WASM
Podemos usar el archivo Program.cs para registrar servicios personalizados tanto para la aplicación Blazor Wasm como para la aplicación Blazor Server.
Mire el ejemplo de código del archivo Program.cs para una aplicación Blazor Wasm:
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
await builder.Build().RunAsync();
Mire el ejemplo de código del archivo Program.cs para una aplicación Blazor Server:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor();
builder.Services.AddSingleton<WeatherForecastService>();
var app = builder.Build();
app.UseRouting();
app.Run();
Inyectar un servicio en el componente Blazor
Podemos inyectar un servicio en un componente utilizando los dos métodos siguientes:
- Usando el atributo [Inject] en la clase base.
- Usando la directiva @inject en el componente.
Podemos inyectar múltiples servicios en un solo componente.
Mire el ejemplo que se muestra a continuación para el componente Razor:
@página "/película"
@inject NavigationManager Navegación
<button @onclick="NavigateToPage">Ir a la página</button>
@código {
anular NavigateToPage()
{
Navegación.NavigateTo("/inicio");
}
}
Mire el ejemplo que se muestra a continuación para la clase base:
utilizando Microsoft.AspNetCore.Components;
espacio de nombres BlazorWasmDemo.Client.Pages
{ clase pública RoutingBase: ComponentBase { [Inyectar] NavigationManager público NavigationManager { get; colocar; } = predeterminado!;
[Inyectar] HttpClient Http { get; colocar; } = predeterminado!;} }
Se espera que los servicios inyectados estén disponibles a medida que se inicializa el componente. Por lo tanto, hemos asignado un literal predeterminado con el operador que admite nulos (¡predeterminado!). Si no asignamos un valor predeterminado no nulo, el compilador mostrará un mensaje de advertencia como "La propiedad no anulable debe contener un valor no nulo al salir del constructor". Alternativamente, con .NET SDK versión 7 o posterior, el modificador "requerido", agregado desde C#11, se puede usar para escribir lo siguiente sin recurrir al operador que admite nulos.
[Inyectar] NavigationManager público requerido NavigationManager { get; colocar; }
Utilice la inyección de dependencia en los servicios Blazor.
Podemos usar la inyección del constructor para inyectar un servicio en otro servicio. El atributo [Inject] o la directiva @inject no están disponibles para su uso en la clase de servicio.
Mire el ejemplo que se muestra a continuación:
clase pública MyCustomService
{ HttpClient privado de solo lectura _httpClient;HttpClient privado de solo lectura _httpClient; public MyCustomService(HttpClient httpClient, NavigationManager NavigationManager) { _httpClient = httpClient; _navigationManager = administrador de navegación; } }
Interoperabilidad de JavaScript
La interoperabilidad de JavaScript, también conocida como interoperabilidad de JavaScript, se define como la capacidad de invocar funciones de JavaScript desde métodos .NET y métodos .NET desde funciones de JavaScript.
Llamar a funciones de JavaScript desde métodos .NET
Podemos usar la abstracción IJSRuntime para llamar a funciones de JavaScript desde .NET.
La interfaz IJSRuntime proporciona dos métodos:
- InvokeAsync: se utiliza para llamar a funciones de JavaScript que devuelven cualquier valor u objeto, incluida una Promesa.
- InvokeVoidAsync: se utiliza para llamar a funciones de JavaScript que devuelven nulas o indefinidas.
Podemos agregar el código JavaScript personalizado en wwwroot/index.html en una aplicación Blazor WebAssembly. Podemos agregar el código JavaScript personalizado en Pages/_Host.cshtml en una aplicación Blazor WebAssembly.
Entendamos esto con un ejemplo.
<guión>
ventana.getArraySum = (númeroArray) => {
devuelve numberArray.reduce((a, b) => a + b, 0);
}
</script>
La función getArraySum aceptará una matriz como parámetro y devolverá la suma de todos los elementos de la matriz.
Cree un componente JSDemoBase.razor y agregue el siguiente código en la clase base JSDemoBase.razor.cs.
utilizando Microsoft.AspNetCore.Components;
utilizando Microsoft.JSInterop;
espacio de nombres BlazorWasmDemo.Client.Pages;
clase pública JSDemoBase: ComponentBase
{ [Inyectar] IJSRuntime JSRuntime protegido { get; colocar; } = predeterminado!;
protegido int sumaDeArray = 0;
privado int[] arrayItems = nuevo int[] { 2, 4, 6, 8, 10 };
Tarea asíncrona protegida GetSumOfArray(){ sumOfArray = await JSRuntime.InvokeAsync<int>("getArraySum", arrayItems); } }
Usaremos el método InvokeAsync para invocar la función JS. La función JS devolverá la suma y se asignará a una variable entera sumOfArray.
Este método GetSumOfArray se puede invocar haciendo clic en un botón como se muestra a continuación:
@página "/calljsmétodo"
@hereda JSDemoBase
<button @onclick="GetSumOfArray">Obtener suma de matriz</button>
<p>La suma de los elementos de la matriz es: @sumOfArray</p>
Si queremos invocar los métodos incorporados de JavaScript, podemos usar el siguiente código:
Tarea asíncrona protegida ShowAlert()
{ await JSRuntime.InvokeVoidAsync("alerta", "Me invocan desde código .NET"); }
Tarea asíncrona protegida ShowArrayItems()
{ espera JSRuntime.InvokeVoidAsync("console.table", arrayItems); }
Hemos invocado la función de alerta y le hemos pasado un parámetro de cadena. El método ShowArrayItems invocará la función console.table de JavaScript y pasará los arrayItems que se mostrarán como entrada.
Capturar referencias a elementos HTML
Podemos capturar las referencias a elementos HTML en un componente usando la estructura ElementReference. Se utiliza para representar una referencia a un elemento renderizado.
Para capturar referencias a elementos HTML en un componente, necesitamos agregar un atributo @ref al elemento HTML. Además, defina un campo de tipo ElementReference cuyo nombre coincida con el valor del atributo @ref.
Podemos pasar ElementReference al código JS a través de la interoperabilidad JS. El código JS recibirá una instancia de HTMLElement que podrá utilizar para la manipulación DOM.
Entendamos esto con un ejemplo.
Agregue el siguiente código JS.
<guión>
ventana.showValue = (elemento) => {
alert('Tu nombre es:' + elemento.valor);
}
</script>
Esta función recibirá la referencia de un elemento HTML y mostrará el valor en un cuadro de alerta.
Podemos agregar el siguiente código en la clase base para invocar esta función.
nombre de ElementReference protegido;
Tarea asíncrona protegida ShowName()
{ espera JSRuntime.InvokeVoidAsync("showValue", nombre); }
Podemos usar el atributo @ref en un elemento HTML para capturar la instancia de ElementReference como se muestra en el siguiente código:
<button class="btn btn-primary" @onclick="ShowName">Mostrar nombre</button>
<input type="text" @ref="name" class="form-control" placeholder="Ingresa tu nombre" />
Llamar a métodos estáticos .NET desde funciones de JavaScript
Podemos usar las funciones DotNet.invokeMethod o DotNet.invokeMethodAsync para invocar un método .NET estático desde JS.
El método .NET debe cumplir los siguientes criterios:
- Debe declararse público y estático.
- Debe estar decorado con el atributo [JSInvokable].
Podemos pasar el identificador del método estático, el nombre del ensamblado que contiene el método C# y los argumentos necesarios.
La sintaxis de la función es: DotNet.invokeMethodAsync('{ASSEMBLY NAME}', '{.NET METHOD Name}', {ARGUMENTS});
dónde,
- {ASSEMBLY NAME} es un marcador de posición para el nombre del ensamblado de la aplicación.
- {.NET METHOD Name} es un marcador de posición para el método .NET que se va a invocar.
- {ARGUMENTS} es un marcador de posición para el argumento que el método .Net requiere que se invoque. Este es un parámetro opcional.
Entendamos esto con un ejemplo.
Agregue el siguiente código en el archivo JSDemoBase.razor.cs.
utilizando Microsoft.AspNetCore.Components;
utilizando Microsoft.JSInterop;
espacio de nombres BlazorTutorial.Client.Pages;
clase pública JSDemoBase: ComponentBase
{ [Inyectar] IJSRuntime protegido JSRuntime { get; colocar; } = predeterminado!;
vacío protegido InvokeJSMethod() { JSRuntime.InvokeVoidAsync("printMessageToConsole"); }
[JSInvokable] public static Task<string> PrintMessage() { return Task.FromResult("Me invocan desde JavaScript."); }}
El InvokeJSMethod llamará a una función JS, printMessageToConsole. El método PrintMessage tiene el atributo [JSInvokable]. Este método se declara como público y estático. Esto permitirá que la función JS printMessageToConsole invoque el método PrintMessage.
Agregue un botón en el archivo JSDemoBase.razor como se muestra a continuación:
<button @onclick="InvokeJSMethod">Invocar método .NET estático</button>
Agregue el siguiente código JS.
<guión>
ventana.printMessageToConsole = () => {
DotNet.invokeMethodAsync(BlazorTutorial.Client', 'PrintMessage')
.entonces(datos => {
consola.log(datos);
});
}
</script>
Hemos creado una función JS, printMessageToConsole. Usaremos la función DotNet.invokeMethodAsync para invocar el método C#, PrintMessage. Hemos pasado el nombre del ensamblado como BlazorTutorial.Client.
Llamar al método de instancia del componente
Podemos invocar el método de instancia .NET de un componente Blazor siguiendo los siguientes pasos:
- Genere una referencia de objeto .NET que se pueda pasar a funciones de JavaScript mediante DotNetObjectReference.Create.
- Realice una llamada de método de instancia al componente utilizando el método invokeMethod o invokeMethodAsync de un objeto .NET.
- Asegúrese de que la referencia del objeto .NET también se elimine cuando se elimine el componente.
Entendamos esto con un ejemplo.
Agregue el siguiente código JS.
function displayMessageCallerJS(objectRef, value) {
objectRef.invokeMethodAsync('DisplayMessage', value);
}
Hemos agregado una función displayMessageCallerJS que aceptará dos parámetros llamados objectRef y value. Esta función luego invocará el método DisplayMessage del objeto componente al que hace referencia objectRef y pasará el valor como argumento.
Agregue el siguiente código en el archivo JSDemoBase.razor.cs:
clase pública JSDemoBase: ComponentBase, IDisposable
{
¿DotnetObjectReference privada<JSDemoBase>? referenciaobjeto;
mensaje de cadena protegida = "Haga clic en el botón.";
anulación protegida nula OnInitialized()
{
objectRef = DotNetObjectReference.Create(esto);
}
[JSInvocable]
DisplayMessage público vacío (valor de cadena)
{
mensaje = valor;
EstadoHasCambiado();
}
eliminación pública vacía ()
{
objectRef?.Dispose();
}
}
Hemos declarado una variable de campo objectRef de tipo DotNetObjectReference<JSDemoBase> que representa una referencia de un objeto .NET. Dentro del método de ciclo de vida OnInitialized, estamos creando una referencia de este componente usando el método estático DotNetObjectReference.Create y asignándolo al campo objectRef.
El método InvokeDisplayMessageCallerJS aceptará un parámetro de cadena. Luego, este método llamará a la función JS, displayMessageCallerJS, y pasará el campo de referencia del objeto .NET que hace referencia a este componente como primer argumento y pasará el parámetro de cadena como segundo argumento.
Hemos creado un método de instancia pública, DisplayMessage, que tiene el atributo [JSInvokable] y aceptará parámetros de cadena. Este método de instancia se invocará desde la función JS displayMessageCallerJS. Asignaremos el valor del parámetro al campo de mensaje y luego llamaremos al método StateHasChanged() para notificar al componente sobre el cambio de estado.
Finalmente, implemente la interfaz IDisposable para garantizar que la referencia del objeto .NET que hace referencia al componente en sí también se elimine cuando se elimine este componente. Específicamente, hemos llamado al método Dispose de la referencia del objeto .NET en el método Dispose de este componente.
Agregue un botón en el archivo JSDemoBase.razor como se muestra a continuación:
<button @onclick="@(()=>InvokeDisplayMessageCallerJS("Se hace clic en el botón"))">Llamar al método JS</button>
<br />
<p >@mensaje</p>
Al hacer clic en el botón, llamaremos al método InvokeDisplayMessageCallerJS y pasaremos un valor de cadena como parámetro. El valor actualizado del mensaje se mostrará en la pantalla.
Sigue leyendo
Rellena el formulario para seguir leyendo.