Estensione di markup {x:Bind}

Nota Per informazioni generali sull'uso del data binding nella tua app con {x:Bind} (e per un confronto completo tra {x:Bind} e {Binding}), vedere Informazioni approfondite sul data binding.

L'estensione di markup {x:Bind}, nuova per Windows 10, è un'alternativa a {Binding}. {x:Bind} viene eseguito in meno tempo e meno memoria di {Binding} e supporta un debug migliore.

In fase di compilazione XAML, {x:Bind} viene convertito in codice che otterrà un valore da una proprietà in un'origine dati e lo imposta sulla proprietà specificata nel markup. L'oggetto di associazione può essere configurato facoltativamente per osservare le modifiche apportate al valore della proprietà dell'origine dati e aggiornarsi in base a tali modifiche (Mode="OneWay"). Può anche essere configurato facoltativamente per eseguire il push delle modifiche nel proprio valore nella proprietà di origine (Mode="TwoWay").

Gli oggetti di associazione creati da {x:Bind} e {Binding} sono in gran parte equivalenti a livello funzionale. Ma {x:Bind} esegue codice speciale, che si genera in fase di compilazione e {Binding} usa l'ispezione degli oggetti runtime per utilizzo generico. Di conseguenza, i binding {x:Bind} (spesso definiti binding compilati) hanno ottime prestazioni, eseguono la convalida delle espressioni di binding in fase di compilazione e supportano il debug consentendo di impostare punti di interruzione nei file di codice generati come classe parziale per la pagina. Questi file sono disponibili nella obj cartella, con nomi come (per C#) <view name>.g.cs.

Suggerimento

{x:Bind} ha una modalità predefinita di OneTime, a differenza di {Binding}, che ha una modalità predefinita di OneWay. Questo è stato scelto per motivi di prestazioni, poiché l'uso di OneWay causa la generazione di più codice per associare e gestire il rilevamento delle modifiche. È possibile specificare in modo esplicito una modalità per usare l'associazione OneWay o TwoWay. È anche possibile usare x:DefaultBindMode per modificare la modalità predefinita per {x:Bind} per un segmento specifico dell'albero di markup. La modalità specificata si applica a qualsiasi espressione {x:Bind} su tale elemento e ai relativi elementi figlio, che non specificano in modo esplicito una modalità come parte dell'associazione.

App di esempio che illustrano {x:Bind}

Utilizzo attributo XAML

<object property="{x:Bind}" .../>
-or-
<object property="{x:Bind propertyPath}" .../>
-or-
<object property="{x:Bind bindingProperties}" .../>
-or-
<object property="{x:Bind propertyPath, bindingProperties}" .../>
-or-
<object property="{x:Bind pathToFunction.functionName(functionParameter1, functionParameter2, ...), bindingProperties}" .../>
Termine Descrizione
propertyPath Stringa che specifica il percorso della proprietà per l'associazione. Altre informazioni sono disponibili nella sezione Percorso proprietà di seguito.
Proprietà di associazione
propName=valore[, propName=valore]* Una o più proprietà di associazione specificate usano una sintassi di coppia nome/valore.
propName Nome stringa della proprietà da impostare sull'oggetto binding. Ad esempio, "Convertitore".
value Il valore per cui impostare la proprietà. La sintassi dell'argomento dipende dalla proprietà impostata. Di seguito è riportato un esempio di utilizzo di un valore propName= in cui il valore è un'estensione di markup: Converter={StaticResource myConverterClass}. Per altre info, vedere Proprietà che si possono impostare con la sezione {x:Bind} di seguito.

Esempi

<Page x:Class="QuizGame.View.HostView" ... >
    <Button Content="{x:Bind Path=ViewModel.NextButtonText, Mode=OneWay}" ... />
</Page>

Questo esempio XAML usa {x:Bind} con una proprietà ListView.ItemTemplate. Si noti la dichiarazione di un valore x:DataType.

  <DataTemplate x:Key="SimpleItemTemplate" x:DataType="data:SampleDataGroup">
    <StackPanel Orientation="Vertical" Height="50">
      <TextBlock Text="{x:Bind Title}"/>
      <TextBlock Text="{x:Bind Description}"/>
    </StackPanel>
  </DataTemplate>

Percorso proprietà

PropertyPath imposta il percorso per un'espressione {x:Bind}. Path è un percorso di proprietà che specifica il valore della proprietà, della proprietà secondaria, del campo o del metodo a cui si sta eseguendo l'associazione (origine). È possibile menzionare il nome della proprietà Path in modo esplicito: {x:Bind Path=...}. In alternativa, è possibile ometterlo: {x:Bind ...}.

Risoluzione del percorso delle proprietà

{x:Bind} non usa DataContext come origine predefinita, ma usa la pagina o il controllo utente stesso. Quindi cercherà nel code-behind della pagina o del controllo utente per proprietà, campi e metodi. Per esporre il modello di visualizzazione a {x:Bind}, in genere è necessario aggiungere nuovi campi o proprietà al code-behind per la pagina o il controllo utente. I passaggi in un percorso di proprietà sono delimitati da punti (.) ed è possibile includere più delimitatori per attraversare le sottoproprietà successive. Usare il delimitatore punto indipendentemente dal linguaggio di programmazione usato per implementare l'oggetto a cui è associato.

Ad esempio: in una pagina, Text="{x:Bind Employee.FirstName}" cercherà un membro Employee nella pagina e quindi un membro FirstName nell'oggetto restituito da Employee. Se si associa un controllo elementi a una proprietà che contiene dipendenti di un dipendente, il percorso della proprietà potrebbe essere "Employee.Dependents" e il modello di elemento del controllo elementi si occupa della visualizzazione degli elementi in "Dipendenti".

Per C++/CX, {x:Bind} non può essere associato a campi e proprietà privati nella pagina o nel modello di dati. Per poter essere associabile, è necessario disporre di una proprietà pubblica. L'area di attacco per l'associazione deve essere esposta come classi/interfacce CX in modo da poter ottenere i metadati pertinenti. L'attributo [Bindable] non deve essere necessario.

Con x:Bind non è necessario usare ElementName=xxx come parte dell'espressione di associazione. È invece possibile usare il nome dell'elemento come prima parte del percorso per l'associazione perché gli elementi denominati diventano campi all'interno della pagina o del controllo utente che rappresenta l'origine dell'associazione radice.

Raccolte

Se l'origine dati è una raccolta, un percorso di proprietà può specificare gli elementi nella raccolta in base alla posizione o all'indice. Ad esempio, "Teams[0].Players", dove il valore letterale "[]" racchiude "0" che richiede il primo elemento di una raccolta indicizzata a zero.

Per usare un indicizzatore, il modello deve implementare IList<T> o IVector<T> sul tipo della proprietà che verrà indicizzata. (Si noti che IReadOnlyList<T> e IVectorView<T> non supportano la sintassi dell'indicizzatore. Se il tipo della proprietà indicizzata supporta INotifyCollectionChanged o IObservableVector e l'associazione è OneWay o TwoWay, registrerà e ascolterà le notifiche di modifica su tali interfacce. La logica di rilevamento delle modifiche verrà aggiornata in base a tutte le modifiche alla raccolta, anche se ciò non influisce sul valore indicizzato specifico. Ciò è dovuto al fatto che la logica di ascolto è comune in tutte le istanze della raccolta.

Se l'origine dati è un dizionario o una mappa, un percorso di proprietà può specificare gli elementi nella raccolta in base al nome della stringa. Ad esempio <TextBlock Text="{x:Bind Players['John Smith']}" /> cercherà un elemento nel dizionario denominato "John Smith". Il nome deve essere racchiuso tra virgolette e possono essere usate virgolette singole o doppie. L'accento circonflesso (^) può essere usato come carattere di escape per le virgolette nelle stringhe. In genere è più semplice usare virgolette diverse da quelle usate per l'attributo XAML. (Si noti che IReadOnlyDictionary<T> e IMapView<T> non supportano la sintassi dell'indicizzatore).

Per usare un indicizzatore di stringhe, il modello deve implementare la stringa IDictionary<, la stringa T> o IMap<, T> sul tipo della proprietà che verrà indicizzata. Se il tipo della proprietà indicizzata supporta IObservableMap e l'associazione è OneWay o TwoWay, registrerà e ascolterà le notifiche di modifica su tali interfacce. La logica di rilevamento delle modifiche verrà aggiornata in base a tutte le modifiche alla raccolta, anche se ciò non influisce sul valore indicizzato specifico. Ciò è dovuto al fatto che la logica di ascolto è comune in tutte le istanze della raccolta.

Proprietà associate

Per eseguire l'associazione alle proprietà associate, è necessario inserire la classe e il nome della proprietà tra parentesi dopo il punto. Ad esempio Text="{x:Bind Button22.( Grid.Row)}". Se la proprietà non viene dichiarata in uno spazio dei nomi Xaml, è necessario anteponerla a uno spazio dei nomi xml, che deve essere mappato a uno spazio dei nomi del codice all'inizio del documento.

Cast

Le associazioni compilate sono fortemente tipate e risolveranno il tipo di ogni passaggio in un percorso. Se il tipo restituito non ha il membro, avrà esito negativo in fase di compilazione. È possibile specificare un cast per indicare all'associazione il tipo reale dell'oggetto.

Nel caso seguente, obj è una proprietà di tipo oggetto, ma contiene una casella di testo, quindi è possibile usare Text="{x:Bind ((TextBox)obj). Text}" o Text="{x:Bind obj.(TextBox.Text)}".

Il campo groups3 in Text="{x:Bind ((data:SampleDataGroup)groups3[0]).Title}" è un dizionario di oggetti, quindi è necessario eseguirne il cast a data:SampleDataGroup. Si noti l'uso dei dati xml: prefisso dello spazio dei nomi per il mapping del tipo di oggetto a uno spazio dei nomi del codice che non fa parte dello spazio dei nomi XAML predefinito.

Nota: la sintassi del cast in stile C#è più flessibile rispetto alla sintassi della proprietà associata ed è la sintassi consigliata in futuro.

Cast senza percorso

Il parser di associazione nativo non fornisce una parola chiave da rappresentare this come parametro di funzione, ma supporta il cast senza percorso ,ad esempio {x:Bind (x:String)}), che può essere usato come parametro di funzione. Pertanto, {x:Bind MethodName((namespace:TypeOfThis))} è un modo valido per eseguire ciò che è concettualmente equivalente a {x:Bind MethodName(this)}.

Esempio:

Text="{x:Bind local:MainPage.GenerateSongTitle((local:SongItem))}"

<Page
    x:Class="AppSample.MainPage"
    ...
    xmlns:local="using:AppSample">

    <Grid>
        <ListView ItemsSource="{x:Bind Songs}">
            <ListView.ItemTemplate>
                <DataTemplate x:DataType="local:SongItem">
                    <TextBlock
                        Margin="12"
                        FontSize="40"
                        Text="{x:Bind local:MainPage.GenerateSongTitle((local:SongItem))}" />
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </Grid>
</Page>
namespace AppSample
{
    public class SongItem
    {
        public string TrackName { get; private set; }
        public string ArtistName { get; private set; }

        public SongItem(string trackName, string artistName)
        {
            ArtistName = artistName;
            TrackName = trackName;
        }
    }

    public sealed partial class MainPage : Page
    {
        public List<SongItem> Songs { get; }
        public MainPage()
        {
            Songs = new List<SongItem>()
            {
                new SongItem("Track 1", "Artist 1"),
                new SongItem("Track 2", "Artist 2"),
                new SongItem("Track 3", "Artist 3")
            };

            this.InitializeComponent();
        }

        public static string GenerateSongTitle(SongItem song)
        {
            return $"{song.TrackName} - {song.ArtistName}";
        }
    }
}

Funzioni nei percorsi di associazione

A partire da Windows 10 versione 1607, {x:Bind} supporta l'uso di una funzione come passaggio foglia del percorso di binding. Si tratta di una funzionalità potente per l'associazione dati che consente diversi scenari nel markup. Per informazioni dettagliate, vedere associazioni di funzioni.

Associazione di eventi

L'associazione di eventi è una funzionalità univoca per l'associazione compilata. Consente di specificare il gestore per un evento usando un'associazione, invece di dover essere un metodo sul code-behind. Ad esempio: Click="{x:Bind rootFrame.GoForward}".

Per gli eventi, il metodo di destinazione non deve essere sottoposto a overload e deve anche:

  • Corrispondere alla firma dell'evento.
  • OPPURE non hanno parametri.
  • OPPURE hanno lo stesso numero di parametri di tipi che possono essere assegnati dai tipi dei parametri dell'evento.

Nel code-behind generato, l'associazione compilata gestisce l'evento e la indirizza al metodo sul modello, valutando il percorso dell'espressione di associazione quando si verifica l'evento. Ciò significa che, a differenza delle associazioni di proprietà, non tiene traccia delle modifiche apportate al modello.

Per altre info sulla sintassi delle stringhe per un percorso di proprietà, vedere Sintassi property-path, tenendo presente le differenze descritte qui per {x:Bind}.

Proprietà che è possibile impostare con {x:Bind}

{x:Bind} viene illustrato con la sintassi segnaposto bindingProperties perché sono presenti più proprietà di lettura/scrittura di un Binding che è possibile impostare nell'estensione di markup. Le proprietà possono essere impostate in qualsiasi ordine con coppie di valori propName=delimitate da virgole. Si noti che non è possibile includere interruzioni di riga nell'espressione di associazione. Alcune delle proprietà richiedono tipi che non dispongono di una conversione dei tipi, quindi richiedono estensioni di markup personalizzate annidate all'interno di {x:Bind}.

Queste proprietà funzionano in modo analogo alle proprietà della classe Binding.

Proprietà Descrizione
Percorso Vedere la sezione Percorso proprietà sopra.
Convertitore Specifica l'oggetto convertitore chiamato dal motore di associazione. Il convertitore può essere impostato in XAML, ma solo se si fa riferimento a un'istanza dell'oggetto assegnata in un riferimento all'estensione di markup {StaticResource} a tale oggetto nel dizionario risorse.
ConverterLanguage Specifica la cultura da utilizzare dal convertitore. (Se si sta impostando ConverterLanguage si dovrebbe anche impostare Converter). Le impostazioni cultura sono impostate come identificatore basato su standard. Per altre info, vedere ConverterLanguage.
ConverterParameter Specifica il parametro del convertitore che può essere usato nella logica del convertitore. (Se si sta impostando ConverterParameter si deve anche impostare Converter. La maggior parte dei convertitori usa una logica semplice che ottiene tutte le informazioni necessarie dal valore passato per la conversione e non richiede un valore ConverterParameter. Il parametro ConverterParameter è per le implementazioni del convertitore moderatamente avanzate che hanno più di una logica che esegue la chiave di ciò che viene passato in ConverterParameter. Per altre info possibile scrivere un convertitore che usa valori diversi dalle stringhe, ma questo non è comune, vedere Osservazioni in ConverterParameter.
FallbackValue Specifica un valore da visualizzare quando non è possibile risolvere l'origine o il percorso.
Modalità Specifica la modalità associazione, come una di queste string: "OneTime", "OneWay" o "TwoWay". L'impostazione predefinita "OneTime". Si noti che questo comportamento è diverso dal valore predefinito per {Binding}, ovvero "OneWay" nella maggior parte dei casi.
TargetNullValue Specifica un valore da visualizzare quando il valore di origine viene risolto ma è esplicitamente Null.
BindBack Specifica una funzione da utilizzare per la direzione inversa di un'associazione bidirezionale.
UpdateSourceTrigger Specifica quando eseguire il push delle modifiche dal controllo al modello nelle associazioni TwoWay. Il valore predefinito per tutte le proprietà tranne TextBox.Text è PropertyChanged; TextBox.Text è LostFocus.

Nota

Se si sta convertendo markup da {x:Bind} a {Binding}, Mode {Binding} a {x:Bind}, tenere presente le differenze nei valori predefiniti per la proprietà Mode. x:DefaultBindMode può essere usato per modificare la modalità predefinita per {x:Bind} per un segmento specifico dell'albero di markup. La modalità selezionata si applica a qualsiasi espressione {x:Bind} su tale elemento e ai relativi elementi figlio, che non specificano in modo esplicito una modalità come parte dell'associazione. OneTime è più efficiente di OneWay, perché l'uso di OneWay causerà la generazione di più codice per collegare e gestire il rilevamento delle modifiche.

Osservazioni:

Poiché {x:Bind} usa il codice generato per ottenere i vantaggi, richiede informazioni sul tipo in fase di compilazione. Ciò significa che non è possibile eseguire l'associazione alle proprietà in cui non si conosce il tipo in anticipo. Per questo motivo, non è possibile usare {x:Bind} con la proprietà DataContext, di tipo Object, ed è soggetta anche a modifiche in fase di esecuzione.

Quando si usa {x:Bind} con i modelli di dati, è necessario indicare il tipo a cui è associato impostando un valore x:DataType, come illustrato nella sezione Esempi. È anche possibile impostare il tipo su un'interfaccia o un tipo di classe di base e quindi usare i cast, se necessario, per formulare un'espressione completa.

Le associazioni compilate dipendono dalla generazione di codice. Pertanto, se si usa {x:Bind} in un dizionario risorse, il dizionario risorse deve avere una classe code-behind. Per un esempio di codice, vedere Dizionari risorse con {x:Bind}.

Le pagine e i controlli utente che includono associazioni compilate avranno una proprietà "Bindings" nel codice generato. Ciò include i metodi seguenti:

  • Update() : aggiornerà i valori di tutte le associazioni compilate. Qualsiasi binding unidirezionale/bidirezionale avrà i listener collegati per rilevare le modifiche.
  • Initialize(): se le associazioni non sono già state inizializzate, chiamerà Update() per inizializzare le associazioni
  • StopTracking(): verranno annullati tutti i listener creati per le associazioni unidirezionale e bidirezionale. Possono essere reinizializzati usando il metodo Update().

Nota

A partire da Windows 10 versione 1607, il framework XAML fornisce un convertitore da valori booleani a Visibility. Il convertitore esegue il mapping true al valore di enumerazione Visible e false a Collapsed, quindi puoi associare una proprietà Visibility a un valore booleano senza creare un convertitore. Si noti che non si tratta di una funzionalità dell'associazione di funzioni, ma solo dell'associazione di proprietà. Per usare il convertitore predefinito, la versione minima dell'SDK di destinazione dell'app deve essere 14393 o successiva. Non è possibile usarlo quando l'app è destinata alle versioni precedenti di Windows 10. Per altre info sulle versioni di destinazione, vedere Codice adattivo per la versione.

Suggerimento se è necessario specificare una singola parentesi graffa per un valore, ad esempio in Path o ConverterParameter, farlo precedere da una barra rovesciata: \{. In alternativa, racchiudere l'intera stringa contenente le parentesi graffe che richiedono l'escape in un set di virgolette secondarie, ad esempio ConverterParameter='{Mix}'.

Converter, ConverterLanguage e ConverterLanguage sono tutti correlati allo scenario di conversione di un valore o di un tipo dall'origine di associazione in un tipo o valore compatibile con la proprietà di destinazione dell'associazione. Per altre info ed esempi, vedere la sezione "Conversioni dei dati" di Data binding in modo approfondito.

{x:Bind} è solo un'estensione di markup, senza alcun modo per creare o modificare tali associazioni a livello di codice. Per altre info sulle estensioni di markup, vedere Panoramica di XAML.