Usare i data binding in XAML

Completato

I data binding possono essere dichiarati nel codice o in XAML usando estensioni di markup. Questa unità illustra quest'ultimo approccio, perché è il modo più comune per creare binding. La scelta del linguaggio XAML è dettata da due motivi. In primo luogo, i binding vengono in genere considerati come parte del codice dell'interfaccia utente poiché ottengono i dati per la visualizzazione di tale interfaccia. In secondo luogo, è disponibile un'estensione di markup denominata Binding che semplifica questa operazione.

Che cosa sono i data binding

Un binding consiste nell'associazione di due proprietà. Una si trova nell'interfaccia utente e l'altra nell'oggetto del modello di dati. Se il valore di una delle proprietà viene modificato, l'oggetto di binding può aggiornare il valore dell'altra. In altre parole, i binding sono oggetti con il ruolo di intermediari che eseguono la sincronizzazione dell'interfaccia utente e dei dati. Per identificare i due oggetti interessati, vengono usati i termini origine e destinazione:

  • Origine: può essere costituita da un oggetto di qualsiasi tipo. In pratica, come origine dati si usa in genere un oggetto dati. Per l'oggetto di origine è necessario identificare la proprietà per la partecipazione al binding. Per identificare la proprietà, si imposta la proprietà Path nel binding.

  • Destinazione: La destinazione è una proprietà implementata usando una proprietà speciale denominata BindableProperty. L'oggetto con BindableProperty deve derivare da BindableObject. Tutti i controlli forniti in .NET MAUI derivano da BindableObject e la maggior parte delle relative proprietà è BindableProperties.

Il diagramma seguente illustra il modo in cui il binding costituisce un oggetto intermedio tra due proprietà:

Diagramma che illustra un binding come intermediario tra una proprietà dell'oggetto di origine e una proprietà associabile a un oggetto di destinazione.

Come creare un data binding in XAML

Si esaminerà ora un semplice esempio di binding creato in XAML tramite l'estensione di markup {Binding}. In questo esempio viene definito il binding tra la proprietà WeatherService.Humidity dell'origine e la proprietà Text del controllo dell'interfaccia utente.

<VerticalStackLayout Margin="10">
    <VerticalStackLayout.Resources>
        <ResourceDictionary>
            <services:WeatherService x:Key="myWeatherService" />
        </ResourceDictionary>
    </VerticalStackLayout.Resources>

    <Label Text="{Binding Path=Humidity, Source={StaticResource myWeatherService}}" />
</VerticalStackLayout>

L'origine di associazione è:

  • Un'istanza dell'oggetto del tipo WeatherService. Viene fatto riferimento all'istanza tramite l'estensione XAML {StaticResource ...}, che punta a un oggetto nel dizionario risorse del layout dello stack.

  • Path punta a una proprietà denominata Humidity nel tipo WeatherService.

    Path è il primo parametro senza nome nella sintassi {Binding} e la sintassi Path= può essere omessa. Questi due binding sono equivalenti:

    <Label Text="{Binding Path=Humidity, Source={StaticResource myWeatherService}}" />
    <Label Text="{Binding Humidity, Source={StaticResource myWeatherService}}" />
    

La destinazione del binding è:

  • Il controllo Label.
  • Proprietà Text del controllo.

Quando viene visualizzata l'interfaccia utente, l'estensione XAML {Binding} crea un binding tra WeatherService e Label. Il binding legge il valore della proprietà WeatherService.Humidity nella proprietà Label.Text.

Usare un altro controllo come origine di associazione

Una funzionalità utile del binding è la possibilità di eseguire il binding ad altri controlli. Il codice XAML seguente è una semplice dimostrazione:

<VerticalStackLayout HorizontalOptions="Center" VerticalOptions="Center">
    <Label x:Name="TargetLabel" Text="TEXT TO ROTATE" BackgroundColor="Yellow" />
    <Slider WidthRequest="100" Maximum="360"
            Value="{Binding Rotation, Mode=OneWayToSource, Source={x:Reference TargetLabel}}" />
</VerticalStackLayout>

La proprietà Slider.Value è associata alla proprietà Label.Rotation, ma in modo diverso rispetto a quanto spiegato in precedenza. Questa proprietà usa la modalità di associazione OneWayToSource, che inverte il meccanismo di associazione tipico. Invece dell'Origine che aggiorna la Destinazione, OneWayToSource aggiorna l'Origine quando la Destinazione cambia. In questo esempio quando il dispositivo di scorrimento si sposta, viene aggiornata la rotazione dell'etichetta in base al valore del dispositivo di scorrimento, come illustrato nell'animazione seguente:

Immagine animata di un dispositivo di scorrimento trascinato con un mouse. Quando il dispositivo di scorrimento si sposta, un frammento di testo ruota in modo che corrisponda alla posizione del dispositivo di scorrimento.

Lo scenario tipico per il binding di controlli l'uno all'altro è costituito dai casi in cui un controllo, in genere un controllo raccolta, ad esempio ListView o CarouselView, include un elemento selezionato che si vuole usare come origine dati. Nell'esempio di una pagina che visualizza le previsioni meteo, potrebbe essere presente un elemento ListView che presenta una previsione di cinque giorni. Quando l'utente seleziona un giorno nell'elenco, i dettagli delle previsioni meteo vengono visualizzati in altri controlli. Se l'utente seleziona un altro giorno, gli altri controlli vengono aggiornati di nuovo con i dettagli del giorno selezionato.

Usare la stessa origine per più binding

L'esempio precedente ha illustrato l'uso di una risorsa statica come origine per un singolo binding. Tale origine può essere usata in più binding. Di seguito è riportato un esempio di dichiarazione di un binding tra tre controlli diversi, tutti associati allo stesso oggetto e proprietà Path, anche se alcuni omettono la proprietà Path:

<VerticalStackLayout Margin="10">
    <VerticalStackLayout.Resources>
        <vm:SimpleWeatherServiceObject x:Key="myWeatherService" />
    </VerticalStackLayout.Resources>
    <Entry Text="{Binding Humidity, Source={StaticResource myWeatherService}}" />
    <Label Text="{Binding Path=Humidity, Source={StaticResource myWeatherService}}" />
</VerticalStackLayout>

Non è necessario usare lo stesso Path quando si usa lo stesso Source:

<VerticalStackLayout Margin="10">
    <VerticalStackLayout.Resources>
        <vm:SimpleWeatherServiceObject x:Key="myWeatherService" />
    </VerticalStackLayout.Resources>
    <Entry Text="{Binding Temperature, Source={StaticResource myWeatherService}}" />
    <Label Text="{Binding Path=Humidity, Source={StaticResource myWeatherService}}" />
</VerticalStackLayout>

Raramente si presenta un singolo dato da un'origine, anche se può verificarsi. In genere sono disponibili diversi controlli che usano dati diversi dalla stessa origine. Questa situazione è così comune che la classe BindableObject ha una proprietà denominata BindingContext che funziona come origine per il data binding. Tenere presente che i controlli di .NET MAUI ereditano dalla classe BindableObject, pertanto i controlli di .NET MAUI hanno la proprietà BindingContext.

L'impostazione di Source del binding è facoltativa. Un binding che non ha Source impostato cerca automaticamente BindingContext nella struttura ad albero visuale XAML. Questo valore è impostato in XAML o assegnato a un elemento padre in base al codice. I binding vengono valutati seguendo questo modello:

  1. Se il binding definisce Source, tale origine viene usata e la ricerca si arresta. Path del binding viene applicato a Source per ottenere un valore. Se Source non è impostato, inizia la ricerca per un'origine di associazione.

  2. La ricerca inizia con l'oggetto di destinazione stesso. Se BindingContext dell'oggetto di destinazione non è Null, la ricerca si arresta e Path del binding viene applicato a BindingContext per ottenere un valore. Se BindingContext è Null, la ricerca continua.

  3. Questo processo continua finché non viene raggiunta la radice XAML. La ricerca termina controllando BindingContext della radice per verificare se è presente un valore non Null. Se non è stato trovato alcun BindingContext valido, il binding non ha alcun elemento a cui associarsi e non esegue alcuna operazione.

BindingContext viene comunemente impostato a livello dell'oggetto radice, in modo da essere applicato all'intero codice XAML.

Esiste un'ultima funzionalità interessante che vale la pena di indicare. I binding controllano se sono state apportate modifiche al riferimento all'oggetto della loro origine. Questo approccio funziona anche per i binding che usano BindingContext come origine. Se la proprietà Source o BindingContext viene riassegnata a un altro oggetto, i binding recuperano i dati dalla nuova origine e aggiornano la destinazione.

Verificare le conoscenze

1.

Quale affermazione è corretta in merito all'oggetto di origine in un binding di .NET MAUI?

2.

Quale affermazione è corretta in merito alla proprietà di destinazione in un binding di .NET MAUI?

3.

Se tutti i binding definiti nei controlli all'interno di un elemento Grid necessitano dello stesso oggetto di origine, quale è la strategia più sicura per impostare tale oggetto una sola volta?