DEV Community

Cover image for Il Binding in Blazor
Marco Santoni
Marco Santoni

Posted on • Updated on

Il Binding in Blazor

Uno degli aspetti fondamentali da conoscere se si vuole sviluppare applicazioni con Blazor (e con altri framework) è il Binding.

Che cosa è il Binding?

Per cominciare vorrei (e dovrei) darvi una definizione di cosa è il Binding ma, sono sincero, per quanto banale non sono riuscito a scrivere due righe per spiegare in maniera chiara e semplice cosa sia questo Binding. Ho cercato anche sui motori di ricerca per aiutarmi un po' ma non sono riuscito a trovare nulla, per cui, permettetemi di darvi una definizione un po' approssimativa che però dettaglieremo nel corso di questo post quando entreremo nel pratico con gli esempi e vi prometto che sarà tutto più chiaro.

Il Binding è quel meccanismo che per esempio ci permette di mostrare il contenuto di una variabile del nostro componente sulla UI (e viceversa se modificato) senza dovercene occupare noi manualmente.

Iniziamo

Ricordate l'esempio che abbiamo sviluppato nel corso del post dal titolo Struttura e funzionamento di un'applicazione Balzor Server? All'interno del componente avevamo dichiarato la variabile title che conteneva un valore, la stringa "Hello World from Blazor Server!". Riprendiamo il componente e dividiamolo in due parti: la parte di codice HTML e la parte di codice C#.

Codice HTML del componente.
<h1>@title</h1>

@if (_list.Count == 0)
{
    <p>In your list there is no elements.</p>
}
else
{
    <p>In your list there @(_list.Count == 1 ? "is 1 element" : $"are {_list.Count} elements").</p>
}

<button @onclick="AddToList_OnClick">Add to list</button>
<button @onclick="RemoveFromList_OnClick">Remove from list</button>

<ul>
    @foreach (string s in _list)
    {
        <li>@s</li>
    }
</ul>
Enter fullscreen mode Exit fullscreen mode
Codice C# del componente.
@code {
    private string title = "Hello World from Blazor Server!";
    private List<string> _list = new List<string>();

    private void AddToList_OnClick()
    {
        int count = _list.Count;
        _list.Add($"Item {++count}");
    }

    private void RemoveFromList_OnClick()
    {
        if (_list.Count == 0)
        {
            return;
        }

        int lastIdx = _list.Count;
        _list.RemoveAt(--lastIdx);
    }
}
Enter fullscreen mode Exit fullscreen mode

Come possiamo vedere, nel codice C# abbiamo inizializzato con un testo la variabile title che poi abbiamo utilizzato nel codice HTML all'interno di un elemento h1 anteponendo il carattere @ al nome. In questo modo abbiamo indicato che vogliamo che in quel punto del componente venga mostrato il contenuto di title.

Questo modo di "stampare a video" il valore di una variabile è chiamato One-Way Binding in quanto il flusso del dato va da e verso una sola direzione, ovvero, dal componente (Codice C#) al DOM (Codice HTML).

Vediamolo di capire meglio con un esempio: modifichiamo il componente lasciando l'elemento h1 invariato ed aggiungiamo un elemento input in cui andremo a mostrare anche qui valore della variabile title.

Codice HTML del componente.
<h1>@title</h1>

<div>
    <label>Enter a text for <code>title</code>:</label>
    <input type="text" value="@title">
</div>
Enter fullscreen mode Exit fullscreen mode

Eseguiamo l'applicazione e vediamo che sia nel titolo (elemento h1) che nella casella di testo (elemento input) viene mostrata la stringa contenuta nella variabile title. Facciamo una qualsiasi modifica al testo e vediamo che però il valore della variabile title non cambia.

Questo è dovuto al fatto che quando si utilizza un Binding unilaterale, in fase di render del componente, il Blazor Engine, sostituisce con del puro testo il nome della variabile perdendo così ogni riferimento con essa.

Abbiamo quindi capito che il One-Way Binding può operare in una sola direzione alla volta ma, attenzione, non vi è una sola direzione! Questa può anche essere contraria, ovvero, dal DOM (Codice HTML) al componente (Codice C#). Inoltre, il binding non serve esclusivamente per mostrare i valori ma può essere anche utilizzato, ad esempio, per gestire eventi (in questo caso si parla di Event Binding). Proseguiamo e vediamo un po' meglio di cosa si tratta.

Event Binding

Partiamo sempre dal componente e vediamo che nel codice HTML avevamo due pulsanti Add to list e Remove from list che, al verificarsi dell'evento click, eseguivano un metodo (AddToList_OnClick o RemoveFromList_OnClick a seconda del pulsante premuto) per modificare la lista degli items. Questa associazione tra l'elemento button ed il codice C# è gestita tramite l'attributo onclick che chi ha lavorato almeno una volta con JavaScript credo conosca bene.

Prestiamo però attenzione ad un particolare: come per la variabile title anche qui al nome dell'attributo (onclick) viene anteposto il carattere @. In questo modo, tramite la sintassi di Razor, abbiamo associato all'evento click dei button uno specifico metodo C#.

Sintassi Razor per associare un evento

@on{DOM Event}={Delegate}


Proviamo ora ad aggiungere un pulsante che, quando premuto, modifica il contenuto della variabile title.

Per non allungare troppo riporto solo le parti del componente interessate dalla modifica e dal contesto.

<h1>@title</h1>

<button @onclick="EditTitleText_OnClick">Edit title</button>
Enter fullscreen mode Exit fullscreen mode
private string title = "Hello World from Blazor Server!";

private void EditTitleText_OnClick()
{
    title = "This is the new text that i chose to set.";
}
Enter fullscreen mode Exit fullscreen mode

Proviamo il codice e vediamo subito che questa volta funziona, il valore della variabile title è stato modificato e la UI a sua volta è stata aggiornata con la nuova stringa.

Facciamo ora un ultimo esempio di come possiamo sfruttare il One-Way Binding. Diciamo che vogliamo "migliorare la UIX" (User Interface Experience) della nostra applicazione facendo sì che il pulsante Remove from list sia disabilitato se non c'è nulla nella lista da rimuovere in modo da risparmiare click inutili all'utente, infatti, al momento questo è sempre attivo ma se non ci sono items non fa nulla. In HTML per disabilitare un elemento è sufficiente aggiungere l'attributo disabled. L'unica cosa che noi dobbiamo fare è condizionare la presenza di questo tag ad una specifica situazione (ovvero, se nella lista c'è almeno un items).

<button @onclick="RemoveFromList_OnClick" disabled="@(_list.Count == 0)">Remove from list</button>
Enter fullscreen mode Exit fullscreen mode

Ed ecco fatto. Non credo ci sia bisogno di scrivere altro. Provate a testare! 😀

Ora però è arrivato il momento di fare un passo avanti e fare la conoscenza del Two-Way Binding che, come possiamo facilmente intuire, è il modo in cui possiamo avere un Binding bidirezionale tra il componente ed il DOM.

Riprendiamo l'esempio dove di prima, dove avevamo aggiunto una casella di testo che volevamo usare per modificare il contenuto di title e facciamo una piccola modifica: sostituiamo l'attributo value con l'attributo @bind e specifichiamo fin da subito subito quale sarà l'evento che scatenerà il binding, ovvero, l'evento oninput.

<h1>@title</h1>

<div>
    <label>Enter a text for <code>title</code>:</label>
    <input type="text" @bind="@title" @bind:event="oninput">
</div>
Enter fullscreen mode Exit fullscreen mode

Con @bind abbiamo creato un "collegamento" tra l'elemento input e la variabile title mentre, con @bind:{event}, abbiamo specificato con quale evento deve avvenire il binding (oninput). Se non avessimo specificato @bind:{event}, Blazor, avrebbe utilizzato di default l'evento onchange.

Facciamo una prova e questa volta vediamo che alla modifica nella casella di testo anche il titolo viene modificato.

Concludiamo l'argomento Two-Way Binding, solo per completezza dell'articolo, dicendo che per fare quanto abbiamo fatto è possibile utilizzare anche un altra sintassi, un po' più verbosa, che produce lo stesso risultato. Vediamola con un esempio.

<h1>@title</h1>

<div>
    <label>Enter a text for <code>title</code>:</label>
    <input type="text" value="@title" @oninput="(e) => title = e.Value.ToString()">
</div>
Enter fullscreen mode Exit fullscreen mode

Aggiornamento manuale

In alcuni casi, potrebbe essere necessario occuparci noi manualmente di notificare a Blazor che qualcosa è cambiato e c'è bisogno di aggiornare la pagina. Un caso potrebbe essere quando utilizziamo dei task in background. Questo lo possiamo fare con StateHasChanged. Di seguito un semplice esempio.

<span>@counter</span>

<button @onclick="StartCounter_OnClick">Start counter</button>
Enter fullscreen mode Exit fullscreen mode
@code {
    private int counter;

    protected override void OnInitialized()
    {
        base.OnInitialized();

        counter = 0;
    }

    private void StartCounter_OnClick(MouseEventArgs e)
    {
        Timer t = new Timer(
            callback: (x) =>
            {
                counter++;
                InvokeAsync(() => StateHasChanged());
            },
            state: null,
            dueTime: TimeSpan.FromSeconds(1),
            period: TimeSpan.FromSeconds(1));

    }
}
Enter fullscreen mode Exit fullscreen mode

Nell'esempio abbiamo notificato il cambiamento con StateHasChanged dello stato utilizzando InvokeAsync. Questo è necessario perché stiamo chiamando StateHasChanged in un thread che non è quello della UI.

Conclusioni

In questo post abbiamo visto un po' come funziona il Binding in Blazor e come possiamo utilizzarlo nelle nostre applicazioni.

Come al solito vi chiedo di scrivere nei commenti cosa ne pensate e di darmi suggerimenti su come migliorare.

Discussion (0)