Condividere dati nelle applicazioni Blazor

Completato

Blazor offre diversi modi per condividere informazioni tra i componenti. È possibile usare i parametri del componente o i parametri a cascata per inviare valori da un componente padre a un componente figlio. Il modello AppState è un altro approccio che può essere usato per archiviare i valori e accedervi da qualsiasi componente nell'applicazione.

Si supponga di lavorare al nuovo sito Web di una pizzeria da asporto. Nella home page devono essere visualizzate più pizze nello stesso modo. Si vogliono visualizzare le pizze eseguendo il rendering di un componente figlio per ogni pizza. Si vuole passare un ID al componente figlio che determina la pizza che verrà visualizzata. Si vuole anche archiviare e visualizzare un valore su più componenti che indica il numero totale di pizze vendute oggi.

In questa unità verranno illustrate tre tecniche diverse che è possibile usare per condividere i valori tra due o più componenti Blazor.

Condivisione di informazioni con altri componenti mediante i parametri del componente

In un'app Web Blazor ogni componente esegue il rendering di una parte di HTML. Alcuni componenti eseguono il rendering di una pagina completa, mentre altri eseguono il rendering di frammenti di markup più piccoli, ad esempio una tabella, un modulo o un singolo controllo. Se il componente esegue il rendering di una sola sezione di markup, è necessario usarlo come componente figlio all'interno di un componente padre. Il componente figlio può anche essere padre di altri componenti più piccoli che vengono sottoposti a rendering al suo interno. I componenti figlio sono noti anche come componenti annidati.

In questa gerarchia di componenti padre e figlio è possibile condividere le informazioni tramite i parametri del componente. Definire questi parametri nei componenti figlio e quindi impostarne i valori nel componente padre. Ad esempio, se si ha un componente figlio che visualizza le foto delle pizze, è possibile usare un parametro del componente per passare l'ID pizza. Il componente figlio cerca la pizza dall'ID e ottiene immagini e altri dati. Se si vogliono visualizzare più pizze diverse, è possibile usare questo componente figlio più volte nella stessa pagina padre, passando un ID diverso a ogni componente figlio.

Per iniziare, definire il parametro del componente nel componente figlio. È definito come una proprietà C# pubblica e decorato con l'attributo [Parameter]:

<h2>New Pizza: @PizzaName</h2>

<p>@PizzaDescription</p>

@code {
    [Parameter]
    public string PizzaName { get; set; }
    
    [Parameter]
    public string PizzaDescription { get; set; } = "The best pizza you've ever tasted."
}

Poiché i parametri del componente sono membri del componente figlio, è possibile eseguirne il rendering nel codice HTML usando il simbolo riservato @ di Blazor, seguito dal relativo nome. Il codice precedente specifica anche un valore predefinito per il parametro PizzaDescription. Questo valore viene sottoposto a rendering se il componente padre non passa un valore. In caso contrario, viene sostituito dal valore passato dal componente padre.

È anche possibile usare classi personalizzate nel progetto come parametri del componente. Si consideri questa classe che descrive un condimento:

public class PizzaTopping
{
    public string Name { get; set; }
    public string Ingredients { get; set; }
}

È possibile usarla come parametro del componente nello stesso modo in cui un valore di parametro consente di accedere alle singole proprietà della classe usando la sintassi con punto:

<h2>New Topping: @Topping.Name</h2>

<p>Ingredients: @Topping.Ingredients</p>

@code {
    [Parameter]
    public PizzaTopping Topping { get; set; }
}

Nel componente padre impostare i valori di parametro usando gli attributi dei tag del componente figlio. Impostare direttamente i componenti semplici. Con un parametro basato su una classe personalizzata, usare il codice C# inline per creare una nuova istanza di tale classe e impostarne i valori:

@page "/pizzas-toppings"

<h1>Our Latest Pizzas and Topping</h1>

<Pizza PizzaName="Hawaiian" PizzaDescription="The one with pineapple" />

<PizzaTopping Topping="@(new PizzaTopping() { Name = "Chilli Sauce", Ingredients = "Three kinds of chilli." })" />

Condividere informazioni usando i parametri a cascata

I parametri del componente funzionano correttamente quando si vuole passare un valore all'elemento figlio immediato di un componente. Le cose si complicano quando si ha una gerarchia profonda con figli di figli e così via. I parametri del componente non vengono passati automaticamente ai componenti nipote dai componenti predecessori o dai componenti che si trovano più in basso nella gerarchia. Per risolvere in modo efficace questo problema, Blazor offre i parametri a cascata. Quando si imposta il valore di un parametro a cascata in un componente, il relativo valore viene reso automaticamente disponibile per tutti i componenti discendenti a qualsiasi profondità.

Nel componente padre l'uso del tag <CascadingValue> consente di specificare le informazioni che verranno propagate a tutti i discendenti. Questo tag viene implementato come componente Blazor predefinito. Qualsiasi componente sottoposto a rendering all'interno di tale tag è in grado di accedere al valore.

@page "/specialoffers"

<h1>Special Offers</h1>

<CascadingValue Name="DealName" Value="Throwback Thursday">
    <!-- Any descendant component rendered here will be able to access the cascading value. -->
</CascadingValue>

Nei componenti discendenti è possibile accedere al valore a cascata usando i membri del componente e decorandoli con l'attributo [CascadingParameter].

<h2>Deal: @DealName</h2>

@code {
    [CascadingParameter(Name="DealName")]
    private string DealName { get; set; }
}

In questo esempio il tag <h2> ha quindi il contenuto Deal: Throwback Thursday, perché tale valore a cascata è stato impostato da un componente predecessore.

Nota

Come per i parametri del componente, è possibile passare oggetti come parametri a cascata in presenza di requisiti più complessi.

Nell'esempio precedente, il valore a cascata viene identificato dall'attributo Name nel componente padre, che corrisponde al valore Name nell'attributo [CascadingParameter]. Facoltativamente, è possibile omettere questi nomi. In tal caso, la corrispondenza degli attributi è basata sul tipo. L'omissione del nome funziona bene quando si ha un solo parametro di quel tipo. Se si vuole eseguire la propagazione di due valori stringa diversi, è necessario usare i nomi dei parametri per evitare ambiguità.

Condividere informazioni con AppState

Un altro approccio alla condivisione delle informazioni tra componenti diversi prevede l'uso del modello AppState. Creare una classe che definisce le proprietà da archiviare e registrarla come servizio con ambito. In qualsiasi componente in cui si vogliono impostare o usare i valori AppState, inserire il servizio per poter accedere alle relative proprietà. A differenza dei parametri del componente e dei parametri a cascata, i valori in AppState sono disponibili per tutti i componenti dell'applicazione, inclusi quelli che non sono elementi figlio del componente che ha archiviato il valore.

Si consideri ad esempio questa classe che archivia un valore relativo alle vendite:

public class PizzaSalesState
{
    public int PizzasSoldToday { get; set; }
}

È necessario aggiungere la classe come servizio con ambito nel file Program.cs:

...
// Add services to the container
builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor();

// Add the AppState class
builder.Services.AddScoped<PizzaSalesState>();
...

A questo punto, in qualsiasi componente in cui si vogliono impostare o recuperare i valori AppState, è possibile inserire la classe e quindi accedere alle proprietà:

@page "/"
@inject PizzaSalesState SalesState

<h1>Welcome to Blazing Pizzas</h1>

<p>Today, we've sold this many pizzas: @SalesState.PizzasSoldToday</p>

<button @onclick="IncrementSales">Buy a Pizza</button>

@code {
    private void IncrementSales()
    {
        SalesState.PizzasSoldToday++;
    }
}

Nota

Questo codice implementa un contatore che viene incrementato quando l'utente seleziona un pulsante, come nell'esempio descritto nell'Esercitazione Blazor: Compilare la prima app Blazor. La differenza è che, in questo caso, poiché il valore del contatore è stato archiviato in un servizio con ambito AppState, il conteggio viene mantenuto tra i caricamenti di pagina e può essere visualizzato da altri utenti.

Nell'unità successiva si proverà a eseguire queste operazioni da soli.

Verificare le conoscenze

1.

I componenti Blazor possono ricevere input usando due tipi di parametri. Quali sono?

2.

AppState può essere registrato con il localizzatore di servizi usando una di queste istruzioni. Quale?