Saltar al contenido

Artículos, tutoriales, trucos, curiosidades, reflexiones y links sobre programación web ASP.NET Core, MVC, Blazor, SignalR, Entity Framework, C#, Azure, Javascript... y lo que venga ;)

18 años online

el blog de José M. Aguilar

Inicio El autor Contactar

Artículos, tutoriales, trucos, curiosidades, reflexiones y links sobre programación web
ASP.NET Core, MVC, Blazor, SignalR, Entity Framework, C#, Azure, Javascript...

¡Microsoft MVP!
martes, 6 de octubre de 2020
Blazor Los parámetros son el mecanismo básico de comunicación entre componentes, pues permiten que un componente padre o contenedor puede especificar, utilizando atributos, los valores que desea enviar de forma individualizada a los componentes utilizados en su interior. Un ejemplo lo vemos en el siguiente bloque de código, donde indicamos a un componente el número de veces que debe mostrar un contenido:
<NumberList Count="10" />
Desde el punto de vista del componente <NumberList>, la recepción de este parámetro es trivial, simplemente indicando el atributo [Parameter] en su propiedad pública Count:
<ul>
@for (int i = 0; i < Count; i++)
{
    <li>@i</li>
}
</ul>
@code {
    [Parameter]
    public int Count { get; set; }
}
Estructura jerárquica de componentes Este mecanismo va bien si queremos pasar el parámetro a un componente específico mediante atributos, pero puede haber ocasiones en las que nos interesa pasar parámetros a todos los componentes que se encuentren por debajo en la estructura jerárquica sin tener que ir pasándolos de uno en uno. Esto puede ser especialmente útil si, como en el diagrama, existen varios niveles de componentes en los que deseamos tener acceso a la misma información.

¡Bienvenidos a los cascading values and parameters, o valores y parámetros en cascada!

Pasar valores a todos los componentes descendientes

Cuando un componente necesita pasar valores a todos los componentes que se encuentren por debajo de él en el árbol, debe utilizar la etiqueta <CascadingValue> como se muestra a continuación:
<CascadingValue Value="UserInfo">
    <UserHeader>...</UserHeader>
    <UserDetails>...</UserDetails>
</CascadingValue>

@code {
    // UserInfo podríamos obtenerlo de algún sitio
    private UserInformation UserInfo = new UserInformation() { Name="José M. Aguilar" }
}
Fijaos que en Value podemos introducir cualquier tipo de objeto .NET, incluso expresiones o referencias al componente actual como Value="this".
Lo que conseguimos con <CascadingValue> es añadir a la cascada un valor de tipo UserInformation que los descendientes podrán obtener directamente declarando un parámetro en cascada, como se puede ver a continuación:
@* File: UserDetails.razor *@
<h2>User details</h2>
@UserInfo.Name

@code {
    [CascadingParameter]
    public UserInformation UserInfo { get; set; }
}
El funcionamiento es idéntico a los parámetros tradicionales expresados como atributos al instanciar el componente, exceptuando que aquí usamos [CascadingParameter] para indicar que el parámetro debe ser poblado desde los valores introducidos en la cascada en niveles superiores de la jerarquía de componentes.

Los valores de los parámetros decorados con el atributo [CascadingParameter] se enlazarán durante la inicialización del componente a los valores en cascada del mismo tipo definidos en cualquier nivel anterior de la jerarquía de componentes. Así, en el ejemplo anterior, el parámetro UserInfo es enlazado correctamente porque existe un valor en la cascada de tipo UserInformation.

Obviamente esto supondría una limitación en caso de existir más de un valor del mismo tipo, como en el siguiente ejemplo, donde queremos propagar valores para el color de texto y de fondo a los componentes descendientes:
<CascadingValue Value="_backgroundColor">
    <CascadingValue Value="_textColor">
        <Title Text="This is the title"></Title>
        ...
    </CascadingValue>
</CascadingValue>
@code {
    string _backgroundColor = "blue";
    string _textColor = "white";
}
En el bloque de código anterior, fijaos que estamos estableciendo dos valores en cascada de tipo string, pero los componentes descendientes que quieran utilizarlos no tendrán forma de distinguirlos al ser ambos del mismo tipo. La aplicación no fallará, pero los parámetros en cascada no serán poblados.

En estos casos debemos establecer un nombre para los valores en cascada, de forma que luego podamos referirnos a ellos de forma inequívoca:
<h1>Demo page</h1>
<CascadingValue Value="_backgroundColor" Name="BackgroundColor">
    <CascadingValue Value="_textColor" Name="TextColor">
        <Title Text="This is the title"></Title>
    </CascadingValue>
</CascadingValue>

@code {
    string _backgroundColor = "blue";
    string _textColor = "white";
}
Y así, ya desde los componentes que los consumen podremos indicar a qué valores nos referimos en cada caso:
@* File: Title.razor *@
<h2 style="background-color: @BackgroundColor; color: @TextColor">@Text</h2>

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

    [CascadingParameter(Name = "TextColor")]
    public string TextColor { get; set; }
    [CascadingParameter(Name = "BackgroundColor")]
    public string BackgroundColor { get; set; }
}
Por último, vale la pena comentar que el uso de cascading parameters puede tener algo de repercusión en el rendimiento, sobre todo en estructuras muy complejas, pues cada cambio del valor introducido en la cascada obligará a recorrer el árbol de componentes para actualizar los valores. Por esta razón, establecer a cierto la propiedad IsFixed de <CascadingValue> es muy recomendable cuando estemos seguros de que el valor no cambiará, porque así informaremos al framework de que no es necesario que realice su seguimiento:

<CascadingValue Value="LoggedUser" IsFixed="true">
...
Espero que os resulte útil :)

Publicado en Variable not found.

Aún no hay comentarios, ¡sé el primero!