Xamarin.Forms Binding compilati

Download Sample Scaricare l'esempio

Le associazioni compilate vengono risolte più rapidamente rispetto alle associazioni classiche, migliorando quindi le prestazioni del data binding nelle Xamarin.Forms applicazioni.

I data binding presentano due problemi principali:

  1. Non è prevista la convalida in fase di compilazione delle espressioni di binding. I binding vengono invece risolti in fase di runtime. Di conseguenza tutti i binding non validi non vengono rilevati fino alla fase di runtime, quando l'applicazione non si comporta come previsto o vengono visualizzati messaggi di errore.
  2. Non sono efficienti a livelli di costi. I binding vengono risolti in fase di runtime mediante l'ispezione oggetti di carattere generale (reflection) e il carico di lavoro necessario varia a seconda della piattaforma.

Le associazioni compilate migliorano le prestazioni del data binding nelle Xamarin.Forms applicazioni risolvendo le espressioni di associazione in fase di compilazione anziché in fase di esecuzione. Questa convalida delle espressioni di binding in fase di compilazione consente anche agli sviluppatori una risoluzione dei problemi più agevole, perché i binding non validi vengono segnalati come errori di compilazione.

Il processo per l'uso dei binding compilati è il seguente:

  1. Abilitare la compilazione XAML. Per altre informazioni sulla compilazione XAML, vedere Compilazione XAML.
  2. Impostare un attributo x:DataType in un VisualElement sul tipo dell'oggetto al quale VisualElement e gli elementi figlio eseguiranno il binding.

Nota

È consigliabile impostare l'attributo x:DataType sullo stesso livello della gerarchia di visualizzazione sul quale è impostato BindingContext. Tuttavia, questo attributo può essere ridefinito in qualsiasi posizione in una gerarchia di visualizzazione.

Per usare le associazioni compilate, l'attributo x:DataType deve essere impostato su un valore letterale stringa o su un tipo usando l'estensione di x:Type markup. In fase di compilazione XAML, le espressioni di binding non valide vengono segnalate come errori di compilazione. Tuttavia il compilatore XAML segnala un errore di compilazione solo per la prima espressione di binding non valida rilevata. Tutte le espressioni di binding valido definite in VisualElement o negli elementi figlio verranno compilate, indipendentemente dal fatto che BindingContext sia impostato in XAML o nel codice. La compilazione di un'espressione di binding genera codice compilato che ottiene un valore da una proprietà in sourcee lo imposta sulla proprietà in target specificata nel markup. Inoltre a seconda dell'espressione di binding il codice generato potrebbe rilevare modifiche nel valore della proprietà source e aggiornare la proprietà target, nonché eseguire il push delle modifiche dalla proprietà target alla proprietà source.

Importante

I binding compilati sono attualmente disabilitati per le espressioni di binding che definiscono la proprietà Source. Il motivo è che la proprietà Source viene sempre impostata usando l'estensione di markup x:Reference, che non può essere risolta in fase di compilazione.

Usare binding compilati

La pagina Selezione colori compilata illustra l'uso di associazioni compilate tra Xamarin.Forms le visualizzazioni e le proprietà del modello di visualizzazione:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:DataBindingDemos"
             x:Class="DataBindingDemos.CompiledColorSelectorPage"
             Title="Compiled Color Selector">
    ...
    <StackLayout x:DataType="local:HslColorViewModel">
        <StackLayout.BindingContext>
            <local:HslColorViewModel Color="Sienna" />
        </StackLayout.BindingContext>
        <BoxView Color="{Binding Color}"
                 ... />
        <StackLayout Margin="10, 0">
            <Label Text="{Binding Name}" />
            <Slider Value="{Binding Hue}" />
            <Label Text="{Binding Hue, StringFormat='Hue = {0:F2}'}" />
            <Slider Value="{Binding Saturation}" />
            <Label Text="{Binding Saturation, StringFormat='Saturation = {0:F2}'}" />
            <Slider Value="{Binding Luminosity}" />
            <Label Text="{Binding Luminosity, StringFormat='Luminosity = {0:F2}'}" />
        </StackLayout>
    </StackLayout>    
</ContentPage>

L'elemento radice StackLayout crea un'istanza di HslColorViewModel e inizializza la proprietà Color all'interno dei tag proprietà dell'elemento per la proprietà BindingContext. Questa radice StackLayout definisce anche l'attributo x:DataType come tipo viewmodel, a indicare che tutte le espressioni di associazione nella gerarchia di visualizzazione radice StackLayout verranno compilate. Questa operazione può essere verificata modificando una qualsiasi delle espressioni di associazione da associare a una proprietà viewmodel inesistente, che genererà un errore di compilazione. Anche se questo esempio imposta l'attributo x:DataType su un valore letterale stringa, può anche essere impostato su un tipo con l'estensione x:Type di markup. Per altre informazioni sull'estensione x:Type di markup, vedere estensione di markup x:Type.

Importante

L'attributo x:DataType può essere ridefinito in qualsiasi posizione di una gerarchia di visualizzazione.

Gli elementi BoxView e Label e le viste Slider ereditano il contesto di binding da StackLayout. Queste viste sono tutte destinazioni di associazione che fanno riferimento alle proprietà di origine nel modello di visualizzazione. Per la BoxView.Color proprietà e la Label.Text proprietà , i data binding sono OneWay : le proprietà nella visualizzazione vengono impostate dalle proprietà nel modello di visualizzazione. Tuttavia la proprietà Slider.Value usa un binding TwoWay. In questo modo ogni Slider elemento può essere impostato dal modello di visualizzazione e anche per impostare il modello di visualizzazione da ogni Slideroggetto .

Quando l'applicazione viene eseguita per la prima volta, gli BoxViewelementi , Label e Slider gli elementi vengono impostati dal modello di visualizzazione in base alla proprietà iniziale Color impostata quando è stata creata un'istanza del modello di visualizzazione. Ciò viene illustrato negli screenshot seguenti:

Compiled Color Selector

Se si azionano i dispositivi di scorrimento, gli elementi BoxView e Label vengono aggiornati di conseguenza.

Per altre informazioni su questo selettore colori, vedere ViewModels and Property-Change Notifications (ViewModel e notifiche di modifica delle proprietà).

Usare associazioni compilate in un oggetto DataTemplate

I binding in un DataTemplate sono interpretati nel contesto dell'oggetto basato su modelli. Pertanto quando si usano binding compilati in un DataTemplate, DataTemplate deve dichiarare il tipo del relativo oggetto dati usando l'attributo x:DataType.

La pagina Compiled Color List (Elenco colori compilato) visualizza come usare i binding compilati in un DataTemplate:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:DataBindingDemos"
             x:Class="DataBindingDemos.CompiledColorListPage"
             Title="Compiled Color List">
    <Grid>
        ...
        <ListView x:Name="colorListView"
                  ItemsSource="{x:Static local:NamedColor.All}"
                  ... >
            <ListView.ItemTemplate>
                <DataTemplate x:DataType="local:NamedColor">
                    <ViewCell>
                        <StackLayout Orientation="Horizontal">
                            <BoxView Color="{Binding Color}"
                                     ... />
                            <Label Text="{Binding FriendlyName}"
                                   ... />
                        </StackLayout>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
        <!-- The BoxView doesn't use compiled bindings -->
        <BoxView Color="{Binding Source={x:Reference colorListView}, Path=SelectedItem.Color}"
                 ... />
    </Grid>
</ContentPage>

La proprietà ListView.ItemsSource è impostata sulla proprietà NamedColor.All statica. La classe NamedColor usa la reflection .NET per enumerare tutti i campi pubblici statici nella struttura Color e archiviarli con i relativi nomi in una raccolta accessibile dalla proprietà All statica. Di conseguenza l'elemento ListView viene riempito con tutte le istanze NamedColor. Per ogni elemento in ListView il contesto di binding per l'elemento è impostato su un oggetto NamedColor. Gli elementi BoxView e Label in ViewCell sono associati a proprietà NamedColor.

Si noti che DataTemplate definisce l'attributo x:DataType come tipo NamedColor, a indicare che tutte le espressioni di binding nella gerarchia di visualizzazione DataTemplate verranno compilate. È possibile verificare questa impostazione modificando le espressioni di binding per impostare il binding a una proprietà NamedColor inesistente, che produrrà un errore di compilazione. Anche se questo esempio imposta l'attributo x:DataType su un valore letterale stringa, può anche essere impostato su un tipo con l'estensione x:Type di markup. Per altre informazioni sull'estensione x:Type di markup, vedere estensione di markup x:Type.

Quando l'applicazione viene eseguita per la prima volta, ListView viene popolata con istanze NamedColor. Quando viene selezionato un elemento in ListView, la proprietà BoxView.Color viene impostata sul colore dell'elemento selezionato in ListView:

Compiled Color List

Se si selezionano altri elementi in ListView viene aggiornato il colore di BoxView.

Combinare associazioni compilate con associazioni classiche

Le espressioni di binding vengono compilate solo per la gerarchia di visualizzazione in cui è definito l'attributo x:DataType. Al contrario, tutte le viste in una gerarchia in cui l'attributo x:DataType non è definito usa i binding classici. È pertanto possibile combinare binding compilati e classici in una pagina. Ad esempio nella sezione precedente le viste in DataTemplate usano i binding compilati, mentre l'elemento BoxView impostato sul colore selezionato in ListView non usa tali binding.

Un'attenta strutturazione degli attributi x:DataType può dare origine a una pagina che usa binding sia compilati che classici. In alternativa l'attributo x:DataType può essere ridefinito in qualsiasi punto di una gerarchia di visualizzazione come null usando l'estensione di markup x:Null. Questa operazione indica che tutte le espressioni di binding all'interno della gerarchia di visualizzazione useranno i binding classici. La pagina Mixed Bindings (Binding misti) dimostra questo approccio:

<StackLayout x:DataType="local:HslColorViewModel">
    <StackLayout.BindingContext>
        <local:HslColorViewModel Color="Sienna" />
    </StackLayout.BindingContext>
    <BoxView Color="{Binding Color}"
             VerticalOptions="FillAndExpand" />
    <StackLayout x:DataType="{x:Null}"
                 Margin="10, 0">
        <Label Text="{Binding Name}" />
        <Slider Value="{Binding Hue}" />
        <Label Text="{Binding Hue, StringFormat='Hue = {0:F2}'}" />
        <Slider Value="{Binding Saturation}" />
        <Label Text="{Binding Saturation, StringFormat='Saturation = {0:F2}'}" />
        <Slider Value="{Binding Luminosity}" />
        <Label Text="{Binding Luminosity, StringFormat='Luminosity = {0:F2}'}" />
    </StackLayout>
</StackLayout>   

L'elemento radice StackLayout definisce l'attributo x:DataType come tipo HslColorViewModel, a indicare che tutte le espressioni di binding nella gerarchia di visualizzazione radice StackLayout verranno compilate. Tuttavia l'elemento StackLayout interno ridefinisce l'attributo x:DataType come null con l'espressione di markup x:Null. Di conseguenza le espressioni di binding nell'elemento StackLayout interno usano i binding classici. Solo BoxView nell'ambito della gerarchia di visualizzazione radice StackLayout usa i binding compilati.

Per altre informazioni sull'espressione di markup x:Null, vedere Estensione di markup x:Null.

Prestazioni

I binding compilati migliorano le prestazioni di data binding e il vantaggio in termini di prestazioni può variare. Gli unit test rivelano che:

  • Un binding compilato che usa la notifica di modifica delle proprietà (ovvero un binding OneWay, OneWayToSource o TwoWay) viene risolto circa 8 volte più rapidamente rispetto a un binding classico.
  • Un binding compilato che non usa la notifica di modifica delle proprietà (ovvero un binding OneTime) viene risolto circa 20 volte più rapidamente rispetto a un binding classico.
  • L'impostazione di BindingContext per un binding compilato che usa la notifica di modifica delle proprietà (ovvero un binding OneWay, OneWayToSource o TwoWay) è circa 5 volte più rapida rispetto all'impostazione di BindingContext per un binding classico.
  • L'impostazione di BindingContext per un binding compilato che non usa la notifica di modifica delle proprietà (ovvero un binding OneTime) è circa 7 volte più rapida rispetto all'impostazione di BindingContext per un binding classico.

Queste variazioni di prestazioni possono risultare più importanti nei dispositivi mobili a seconda della piattaforma usata, della versione del sistema operativo e del dispositivo in cui viene eseguita l'applicazione.