Dela via


Windows-databindning på djupet

I den här artikeln beskriver vi databindningsfunktionerna för Windows App SDK för DE API:er som finns i namnområdet Microsoft.UI.Xaml.Data.

Anmärkning

I det här avsnittet beskrivs databindningsfunktioner i detalj. En kort, praktisk introduktion finns i Översikt över databindning.

Viktiga API:er

Introduction

Databindning är ett sätt för appens användargränssnitt att visa data och, om så önskas, förbli synkroniserad med dessa data. Med databindning kan du skilja data från användargränssnittets problem, vilket resulterar i en enklare konceptuell modell samt bättre läsbarhet, testbarhet och underhåll av din app.

Du kan använda databindning för att helt enkelt visa värden från en datakälla när användargränssnittet först visas, men inte svara på ändringar i dessa värden. Det här är ett bindningsläge som kallas en gång, och det fungerar bra för ett värde som inte ändras under körningen. Du kan också välja att "observera" värdena och uppdatera användargränssnittet när de ändras. Det här läget kallas enkelriktat och fungerar bra för skrivskyddade data. I slutändan kan du välja att både observera och uppdatera, så att ändringar som användaren gör i värden i användargränssnittet automatiskt skickas tillbaka till datakällan. Det här läget kallas dubbelriktat och fungerar bra för skrivskyddade data. Här följer några exempel.

  • Du kan använda engångsläget för att binda en bild till den aktuella användarens foto.
  • Du kan använda enkelriktat läge för att binda en ListView till en samling nyhetsartiklar i realtid grupperade efter tidningsavsnitt.
  • Du kan använda tvåvägsläget för att binda en textruta till en kunds namn i ett formulär.

Oberoende av läget finns det två typer av bindningar och båda deklareras vanligtvis i UI-markering. Du kan välja att använda markeringstillägget {x:Bind} eller {Binding}-markeringstillägget. Och du kan till och med använda en blandning av de två i samma app, även i samma användargränssnittselement. {x:Bind} var nytt i UWP för Windows 10 och det har bättre prestanda. All information som beskrivs i det här avsnittet gäller för båda typerna av bindningar om vi inte uttryckligen säger något annat.

UWP-exempelappar som demonstrerar {x:Bind}

UWP-exempelappar som demonstrerar {Binding}

Varje bindning omfattar dessa delar

  • En bindningskälla. Det här är källan till data för bindningen, och det kan vara en instans av alla klasser som har medlemmar vars värden du vill visa i användargränssnittet.
  • Ett bindningsmål. Det här är en DependencyProperty för FrameworkElement i ditt användargränssnitt som visar data.
  • Ett bindningsobjekt. Det här är den del som överför datavärden från källan till målet och eventuellt från målet tillbaka till källan. Bindningsobjektet skapas vid XAML-inläsningstid från ditt {x:Bind} eller {Binding} -tillägg.

I följande avsnitt tar vi en närmare titt på bindningskällan, bindningsmålet och bindningsobjektet. Och vi länkar avsnitten tillsammans med exemplet med att binda en knapps innehåll till en strängegenskap med namnet NextButtonText, som tillhör en klass med namnet HostViewModel.

Bindningskälla

Här är en mycket rudimentär implementering av en klass som vi kan använda som bindningskälla.

public class HostViewModel
{
    public HostViewModel()
    {
        NextButtonText = "Next";
    }

    public string NextButtonText { get; set; }
}

Implementeringen av HostViewModel, och dess egenskap NextButtonText, är endast lämplig för engångsbindning. Men enkelriktade och dubbelriktade bindningar är mycket vanliga, och i den typen av bindning uppdateras användargränssnittet automatiskt som svar på ändringar i datavärdena för bindningskällan. För att den typen av bindning ska fungera korrekt måste du göra bindningskällan observerbar för bindningsobjektet. Så i vårt exempel, om vi vill envägs- eller tvåvägsbindning till NextButtonText egenskapen, måste alla ändringar som sker vid körning till värdet för den egenskapen göras observerbara för bindningsobjektet.

Ett sätt att göra det är att härleda den klass som representerar din bindningskälla från DependencyObject och exponera ett datavärde via en DependencyProperty. Det är så ett FrameworkElement blir observerbart. A FrameworkElement är en bra bindningskälla direkt.

Ett enklare sätt att göra en klass observerbar – och ett nödvändigt för klasser som redan har en basklass – är att implementera System.ComponentModel.INotifyPropertyChanged. Detta innebär egentligen bara att implementera en enda händelse med namnet PropertyChanged. Ett exempel på användning HostViewModel finns nedan.

...
using System.ComponentModel;
using System.Runtime.CompilerServices;
...
public class HostViewModel : INotifyPropertyChanged
{
    private string nextButtonText;

    public event PropertyChangedEventHandler PropertyChanged = delegate { };

    public HostViewModel()
    {
        NextButtonText = "Next";
    }

    public string NextButtonText
    {
        get { return nextButtonText; }
        set
        {
            nextButtonText = value;
            OnPropertyChanged();
        }
    }

    public void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        // Raise the PropertyChanged event, passing the name of the property whose value has changed.
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

Nu är egenskapen NextButtonText observerbar. När du skapar en enkelriktad eller dubbelriktad bindning till den egenskapen (vi visar hur senare) prenumererar det resulterande bindningsobjektet på PropertyChanged händelsen. När händelsen utlöses tar bindningsobjektets hanterare emot ett argument som innehåller namnet på den egenskap som har ändrats. Det är så bindningsobjektet vet vilken egenskaps värde som ska läsas och läsas igen.

Så att du inte behöver implementera mönstret som visas ovan flera gånger, om du använder C# kan du bara härleda från basklassen BindableBase som du hittar i QuizGame-exemplet (i mappen "Common"). Här är ett exempel på hur det ser ut.

public class HostViewModel : BindableBase
{
    private string nextButtonText;

    public HostViewModel()
    {
        NextButtonText = "Next";
    }

    public string NextButtonText
    {
        get { return nextButtonText; }
        set { SetProperty(ref nextButtonText, value); }
    }
}

PropertyChanged Att höja händelsen med argumentet String.Empty eller null anger att alla egenskaper som inte är indexerare för objektet ska läsas på nytt. Du kan höja händelsen för att indikera att indexerarens egenskaper för objektet har ändrats med hjälp av argumentet "Item[indexer]" för specifika indexerare (där indexeraren är indexvärdet) eller ett värde av "Item[]" för alla indexerare.

En bindningskälla kan behandlas antingen som ett enskilt objekt vars egenskaper innehåller data eller som en samling objekt. I C#-kod kan du en gång binda till ett objekt som implementerar List<T> för att visa en samling som inte ändras vid körning. För en observerbar samling (observerar när objekt läggs till och tas bort från samlingen) binder envägsbindning till ObservableCollection<T> i stället. Om du vill binda till dina egna samlingsklasser använder du vägledningen i följande tabell.

Scenario C# (CLR) C++/WinRT
Binda till ett objekt. Kan vara valfritt objekt. Kan vara valfritt objekt.
Hämta meddelanden om egenskapsändring från ett bundet objekt. Objektet måste implementera INotifyPropertyChanged. Objektet måste implementera INotifyPropertyChanged.
Binda till en samling. Lista<T> IVector för IInspectable eller IBindableObservableVector. Se XAML-objektkontroller; binda till en C++/WinRT-samling och samlingar med C++/WinRT.
Hämta meddelanden om samlingsändring från en bunden samling. ObservableCollection<T> IObservableVector av IInspectable. Till exempel winrt::single_threaded_observable_vector<T>.
Implementera en samling som stöder bindning. Utöka list-T<> eller implementera IList-, IList-objekt<>, IEnumerable- eller IEnumerable-objekt<>. Bindning till generisk och IList<T>IEnumerable<T> stöds inte. Implementera IVector för IInspectable. Se XAML-objektkontroller; binda till en C++/WinRT-samling och samlingar med C++/WinRT.
Implementera en samling som stöder meddelanden om insamlingsändring. Utöka ObservableCollection<T> eller implementera (icke-generisk) IList och INotifyCollectionChanged. Implementera IObservableVector för IInspectable eller IBindableObservableVector.
Implementera en samling som stöder inkrementell inläsning. Utöka ObservableCollection<T> eller implementera (icke-generisk) IList och INotifyCollectionChanged. Dessutom implementerar du ISupportIncrementalLoading. Implementera IObservableVector för IInspectable eller IBindableObservableVector. Dessutom implementerar du ISupportIncrementalLoading

Du kan binda listkontroller till godtyckligt stora datakällor och fortfarande uppnå höga prestanda med hjälp av inkrementell inläsning. Du kan till exempel binda listkontroller till Bing-bildfrågeresultat utan att behöva läsa in alla resultat samtidigt. I stället läser du bara in vissa resultat omedelbart och läser in ytterligare resultat efter behov. Om du vill ha stöd för inkrementell inläsning måste du implementera ISupportIncrementalLoading på en datakälla som stöder meddelanden om insamlingsändringar. När databindningsmotorn begär mer data måste datakällan göra lämpliga begäranden, integrera resultaten och sedan skicka lämpliga meddelanden för att uppdatera användargränssnittet.

Bindningsmål

I de två exemplen Button.Content nedan är egenskapen bindningsmålet och dess värde är inställt på ett markeringstillägg som deklarerar bindningsobjektet. Först visas {x:Bind} och sedan {Binding}. Att deklarera bindningar i markering är vanligt (det är praktiskt, läsbart och lätt att använda). Men du kan undvika markering och imperativt (programmatiskt) skapa en instans av klassen Bindning i stället om du behöver.

<Button Content="{x:Bind ...}" ... />
<Button Content="{Binding ...}" ... />

Om du använder C++/WinRT måste du lägga till attributet BindableAttribute i valfri körningsklass som du vill använda {Binding} -markeringstillägget med.

Viktigt!

Om du använder C++/WinRT är attributet BindableAttribute tillgängligt med Windows App SDK. Utan det attributet måste du implementera gränssnitten ICustomPropertyProvider och ICustomProperty för att kunna använda markeringstillägget {Binding} .

Bindningsobjekt som deklarerats med {x:Bind}

Det finns ett steg som vi måste göra innan vi skapar vår {x:Bind} -markering. Vi måste exponera vår bindningskällaklass från klassen som representerar vår sida med markering. Det gör vi genom att lägga till en egenskap (av typen HostViewModel i det här fallet) i vår MainWindow fönsterklass.

namespace DataBindingInDepth
{
    public sealed partial class MainWindow : Window
    {
        public MainWindow()
        {
            this.InitializeComponent();
            ViewModel = new HostViewModel();
        }
    
        public HostViewModel ViewModel { get; set; }
    }
}

Nu kan vi titta närmare på markering som deklarerar bindningsobjektet. Exemplet nedan använder samma Button.Content bindningsmål som vi använde i avsnittet "Bindningsmål" tidigare och visar att det är bundet HostViewModel.NextButtonText till egenskapen.

<!-- MainWindow.xaml -->
<Window x:Class="DataBindingInDepth.MainWindow" ... >
    <Button Content="{x:Bind Path=ViewModel.NextButtonText, Mode=OneWay}" ... />
</Window>

Observera värdet som vi anger för Path. Det här värdet tolkas i kontexten för själva fönstret, och i det här fallet börjar sökvägen genom att referera till egenskapen ViewModel som vi precis har lagt till på MainWindow sidan. Den egenskapen returnerar en HostViewModel instans, så vi kan pricka in i objektet för att få åtkomst till HostViewModel.NextButtonText egenskapen. Och vi anger Mode, för att åsidosätta standardvärdet {x:Bind} en gång.

Egenskapen Path stöder en mängd olika syntaxalternativ för bindning till kapslade egenskaper, anslutna egenskaper samt heltals- och strängindexerare. Mer information finns i Syntax för egenskapssökväg. Bindning till strängindexerare ger dig effekten av bindning till dynamiska egenskaper utan att behöva implementera ICustomPropertyProvider. Andra inställningar finns i {x:Bind} markeringstillägg.

För att illustrera att egenskapen HostViewModel.NextButtonText verkligen är observerbar lägger du till en Click händelsehanterare på knappen och uppdaterar värdet HostViewModel.NextButtonTextför . Skapa, kör och klicka på knappen för att se värdet för knappens Content uppdatering.

// MainWindow.xaml.cs
private void Button_Click(object sender, RoutedEventArgs e)
{
    ViewModel.NextButtonText = "Updated Next button text";
}

Anmärkning

Ändringar i TextBox.Text skickas till en tvåvägsbunden källa när textrutan förlorar fokus och inte efter varje tangenttryckning.

DataTemplate och x:DataType

I ett DataTemplate (om det används som en objektmall, en innehållsmall eller en rubrikmall) tolkas inte värdet Path för i fönstrets kontext, utan i kontexten för det dataobjekt som mallas. När du använder {x:Bind} i en datamall, så att dess bindningar kan verifieras (och effektiv kod genereras för dem) vid kompileringstid, DataTemplate måste du deklarera typen av dess dataobjekt med hjälp x:DataTypeav . Exemplet nedan kan användas som en objektkontroll som ItemTemplate är bunden till en samling SampleDataGroup objekt.

<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>

Objekt med svag typ i sökvägen

Anta till exempel att du har en typ med namnet SampleDataGroup, som implementerar en strängegenskap med namnet Title. Och du har en egenskap MainWindow.SampleDataGroupAsObject, som är av typen object, men som faktiskt returnerar en instans av SampleDataGroup. Bindningen <TextBlock Text="{x:Bind SampleDataGroupAsObject.Title}"/> resulterar i ett kompileringsfel eftersom Title egenskapen inte hittas på typen object. Lösningen för detta är att lägga till en gjuten i syntaxen Path så här: <TextBlock Text="{x:Bind ((data:SampleDataGroup)SampleDataGroupAsObject).Title}"/>. Här är ett annat exempel där Element deklareras som object men faktiskt är en TextBlock: <TextBlock Text="{x:Bind Element.Text}"/>. Och en rollbesättning åtgärdar problemet: <TextBlock Text="{x:Bind ((TextBlock)Element).Text}"/>.

Om dina data läses in asynkront

Kod som stöd {x:Bind} genereras vid kompilering i de partiella klasserna för dina fönster. Dessa filer finns i mappen obj med namn som (för C#) <view name>.g.cs. Den genererade koden innehåller en hanterare för fönstrets inläsningshändelse och den hanteraren anropar Initialize metoden för en genererad klass som representerar bindningar i fönstret. Initialize i sin tur anropar Update för att börja flytta data mellan bindningskällan och målet. Loading utlöses strax före det första måttpasset i fönstret eller användarkontrollen. Så om dina data läses in asynkront kanske de inte är klara när de Initialize anropas. När du har läst in data kan du därför framtvinga att engångsbindningar initieras genom att anropa this.Bindings.Update();. Om du bara behöver engångsbindningar för asynkront inlästa data är det mycket billigare att initiera dem på det här sättet än att ha enkelriktade bindningar och lyssna efter ändringar. Om dina data inte genomgår detaljerade ändringar, och om de sannolikt kommer att uppdateras som en del av en specifik åtgärd, kan du göra dina bindningar en gång och framtvinga en manuell uppdatering när som helst med ett anrop till Update.

Anmärkning

{x:Bind} passar inte för sena scenarier, till exempel navigering i ordlistestrukturen för ett JSON-objekt eller ankskrivning. "Anka skriver" är en svag form av att skriva baserat på lexikala matchningar på egenskapsnamn (som i , "om det går, simmar och kvacksalvare som en anka, då är det en anka"). Med ankskrivning skulle en bindning till Age egenskapen vara lika nöjd med ett Person eller ett Wine objekt (förutsatt att dessa typer var och en hade en Age egenskap). I dessa scenarier använder du markeringstillägget {Binding} .

Bindningsobjekt som deklarerats med {Binding}

Om du använder C++/WinRT måste du lägga till attributet BindableAttribute i valfri körningsklass som du vill binda till för att kunna använda tillägget {Binding}. Om du vill använda {x:Bind} behöver du inte det attributet.

// HostViewModel.idl
// Add this attribute:
[Microsoft.UI.Xaml.Data.Bindable]
runtimeclass HostViewModel : Microsoft.UI.Xaml.Data.INotifyPropertyChanged
{
    HostViewModel();
    String NextButtonText;
}

Viktigt!

Om du använder C++/WinRT är attributet BindableAttribute tillgängligt med Windows App SDK. Utan det attributet måste du implementera gränssnitten ICustomPropertyProvider och ICustomProperty för att kunna använda markeringstillägget {Binding} .

{Binding} förutsätter som standard att du binder till DataContext i markeringsfönstret. Därför ska vi ange DataContext att fönstret ska vara en instans av vår bindningskällklass (av typen HostViewModel i det här fallet). Exemplet nedan visar markering som deklarerar bindningsobjektet. Vi använder samma Button.Content bindningsmål som vi använde i avsnittet "Bindningsmål" tidigare och vi binder till HostViewModel.NextButtonText egenskapen.

<Window xmlns:viewmodel="using:DataBindingInDepth" ... >
    <Window.DataContext>
        <viewmodel:HostViewModel x:Name="viewModelInDataContext"/>
    </Window.DataContext>
    ...
    <Button Content="{Binding Path=NextButtonText}" ... />
</Window>
// MainWindow.xaml.cs
private void Button_Click(object sender, RoutedEventArgs e)
{
    viewModelInDataContext.NextButtonText = "Updated Next button text";
}

Observera värdet som vi anger för Path. Det här värdet tolkas i kontexten för fönstrets DataContext, som i det här exemplet är inställt på en instans av HostViewModel. Sökvägen refererar till HostViewModel.NextButtonText egenskapen. Vi kan utelämna Modeeftersom standardvärdet {Binding} för enkelriktad fungerar här.

Standardvärdet för DataContext för ett användargränssnittselement är det ärvda värdet för dess överordnade element. Du kan naturligtvis åsidosätta den standardinställningen DataContext explicit, vilket i sin tur ärvs av underordnade som standard. Att uttryckligen ange DataContext ett element är användbart när du vill ha flera bindningar som använder samma källa.

Ett bindningsobjekt har en Source egenskap som standard är DataContext för det användargränssnittselement som bindningen deklareras för. Du kan åsidosätta den här standardinställningen genom att ange Source, RelativeSourceeller ElementName uttryckligen på bindningen (se {Binding} för mer information).

I en DataTemplate anges DataContext automatiskt till det dataobjekt som mallas. Exemplet nedan kan användas som en objektkontroll som ItemTemplate är bunden till en samling av alla typer som har strängegenskaper med namnet Title och Description.

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

Anmärkning

Som standard skickas ändringar i TextBox.Text till en tvåvägsbunden källa när textrutan förlorar fokus. Om du vill att ändringar ska skickas efter varje användarintryckning anger du UpdateSourceTrigger till PropertyChanged på bindningen i markering. Du kan också helt ta kontroll över när ändringar skickas till källan genom att ange UpdateSourceTrigger till Explicit. Sedan hanterar du händelser i textrutan (vanligtvis TextBox.TextChanged), anropar GetBindingExpression på målet för att hämta ett BindingExpression-objekt och anropar slutligen BindingExpression.UpdateSource för att programmatiskt uppdatera datakällan.

Egenskapen Path stöder en mängd olika syntaxalternativ för bindning till kapslade egenskaper, anslutna egenskaper samt heltals- och strängindexerare. Mer information finns i Syntax för egenskapssökväg. Bindning till strängindexerare ger dig effekten av bindning till dynamiska egenskaper utan att behöva implementera ICustomPropertyProvider. Egenskapen ElementName är användbar för element-till-element-bindning. Egenskapen RelativeSource har flera användningsområden, varav en är ett mer kraftfullt alternativ till mallbindning i ett ControlTemplate. Andra inställningar finns i {Binding}-markeringstillägget och klassen Bindning .

Vad händer om källan och målet inte är av samma typ?

Om du vill styra synligheten för ett användargränssnittselement baserat på värdet för en boolesk egenskap, eller om du vill återge ett gränssnittselement med en färg som är en funktion av ett numeriskt värdes intervall eller trend, eller om du vill visa ett datum- och/eller tidsvärde i en egenskap för användargränssnittselement som förväntar sig en sträng, måste du konvertera värden från en typ till en annan. Det finns fall där rätt lösning är att exponera en annan egenskap av rätt typ från din bindningskällklass och hålla konverteringslogik inkapslad och testbar där. Men det är inte flexibelt eller skalbart när du har stora antal, eller stora kombinationer, av käll- och målegenskaper. I så fall har du ett par alternativ:

  • Om du använder {x:Bind} kan du binda direkt till en funktion för att göra den konverteringen
  • Eller så kan du ange en värdekonverterare som är ett objekt som är utformat för att utföra konverteringen

Värdekonverterare

Här är en värdekonverterare, lämplig för en engångsbindning eller en enkelriktad bindning, som konverterar ett DateTime-värde till ett string värde som innehåller månaden. Klassen implementerar IValueConverter.

public class DateToStringConverter : IValueConverter
{
    // Define the Convert method to convert a DateTime value to 
    // a month string.
    public object Convert(object value, Type targetType, 
        object parameter, string language)
    {
        // value is the data from the source object.
        DateTime thisDate = (DateTime)value;
        int monthNum = thisDate.Month;
        string month;
        switch (monthNum)
        {
            case 1:
                month = "January";
                break;
            case 2:
                month = "February";
                break;
            default:
                month = "Month not found";
                break;
        }
        // Return the value to pass to the target.
        return month;
    }

    // ConvertBack is not implemented for a OneWay binding.
    public object ConvertBack(object value, Type targetType, 
        object parameter, string language)
    {
        throw new NotImplementedException();
    }
}

Och så här använder du värdekonverteraren i din bindningsobjektmarkering.

<UserControl.Resources>
  <local:DateToStringConverter x:Key="Converter1"/>
</UserControl.Resources>
...
<TextBlock Grid.Column="0" 
  Text="{x:Bind ViewModel.Month, Converter={StaticResource Converter1}}"/>
<TextBlock Grid.Column="0" 
  Text="{Binding Month, Converter={StaticResource Converter1}}"/>

Bindningsmotorn anropar metoderna Convert och ConvertBack om parametern Converter har definierats för bindningen. När data skickas från källan anropar Convert bindningsmotorn och skickar returnerade data till målet. När data skickas från målet (för en dubbelriktad bindning) anropar ConvertBack bindningsmotorn och skickar returnerade data till källan.

Konverteraren har också valfria parametrar: ConverterLanguage, som gör det möjligt att ange vilket språk som ska användas i konverteringen, och ConverterParameter, vilket gör det möjligt att skicka en parameter för konverteringslogik. Ett exempel som använder en konverterarparameter finns i IValueConverter.

Anmärkning

Om det finns ett fel i konverteringen ska du inte utlösa ett undantag. Returnera i stället DependencyProperty.UnsetValue, vilket stoppar dataöverföringen.

Om du vill visa ett standardvärde som ska användas när bindningskällan inte kan matchas anger du FallbackValue egenskapen för bindningsobjektet i markering. Detta är användbart för att hantera konverterings- och formateringsfel. Det är också användbart att binda till källegenskaper som kanske inte finns på alla objekt i en bunden samling heterogena typer.

Om du binder en textkontroll till ett värde som inte är en sträng konverterar databindningsmotorn värdet till en sträng. Om värdet är en referenstyp hämtar databindningsmotorn strängvärdet genom att anropa ICustomPropertyProvider.GetStringRepresentation eller IStringable.ToString om det är tillgängligt och anropar annars Object.ToString. Observera dock att bindningsmotorn ignorerar alla ToString implementeringar som döljer basklassimplementeringen. Underklassimplementeringar bör åsidosätta basklassmetoden ToString i stället. På samma sätt verkar alla hanterade objekt på interna språk implementera ICustomPropertyProvider och IStringable. Men alla anrop till GetStringRepresentation och IStringable.ToString dirigeras till Object.ToString eller åsidosätter den metoden och aldrig till en ny ToString implementering som döljer basklassimplementeringen.

Anmärkning

Windows Community Toolkit tillhandahåller en BoolToVisibilityConverter. Konverteraren mappar true till Visible uppräkningsvärdet och false till så att Collapsed du kan binda en Visibility egenskap till ett booleskt värde utan att skapa en konverterare. Om du vill använda konverteraren måste projektet lägga till NuGet-paketet CommunityToolkit.WinUI.Converters .

Funktionsbindning i {x:Bind}

{x:Bind} gör att det sista steget i en bindningssökväg kan vara en funktion. Detta kan användas för att utföra konverteringar och för att utföra bindningar som är beroende av mer än en egenskap. Se Funktioner i x:Bind

Bindning mellan element

Du kan binda egenskapen för ett XAML-element till egenskapen för ett annat XAML-element. Här är ett exempel på hur det ser ut i markering.

<TextBox x:Name="myTextBox" />
<TextBlock Text="{x:Bind myTextBox.Text, Mode=OneWay}" />

Resursordlistor med {x:Bind}

Markeringstillägget {x:Bind} är beroende av kodgenerering, så den behöver en kod bakom fil som innehåller en konstruktor som anropar InitializeComponent (för att initiera den genererade koden). Du använder resursordlistan igen genom att instansiera dess typ (så att den kallas) i stället för att InitializeComponent referera till dess filnamn. Här är ett exempel på vad du kan göra om du har en befintlig resursordlista och vill använda {x:Bind} den.

<!-- TemplatesResourceDictionary.xaml -->
<ResourceDictionary
    x:Class="ExampleNamespace.TemplatesResourceDictionary"
    .....
    xmlns:examplenamespace="using:ExampleNamespace">
    
    <DataTemplate x:Key="EmployeeTemplate" x:DataType="examplenamespace:IEmployee">
        <Grid>
            <TextBlock Text="{x:Bind Name}"/>
        </Grid>
    </DataTemplate>
</ResourceDictionary>
// TemplatesResourceDictionary.xaml.cs
using Microsoft.UI.Xaml.Data;
 
namespace ExampleNamespace
{
    public partial class TemplatesResourceDictionary
    {
        public TemplatesResourceDictionary()
        {
            InitializeComponent();
        }
    }
}
<!-- MainWindow.xaml -->
<Window x:Class="ExampleNamespace.MainWindow"
    ....
    xmlns:examplenamespace="using:ExampleNamespace">

    <Window.Resources>
        <ResourceDictionary>
            .... 
            <ResourceDictionary.MergedDictionaries>
                <examplenamespace:TemplatesResourceDictionary/>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Window.Resources>
</Window>

Blanda {x:Bind} och {Binding} i ett återanvändbart format

I det föregående exemplet som visades i {x:Bind} DataTemplates kan du också skapa återanvändbara formatmallar som kombinerar både {x:Bind} tillägg och {Binding} markeringstillägg. Detta är användbart när du vill binda vissa egenskaper till kompilering av kända värden med hjälp av {x:Bind} och andra egenskaper för att köra DataContext-värden med hjälp av {Binding}.

Här är ett exempel som visar hur du skapar ett återanvändbart knappformat som använder båda bindningsmetoderna:

TemplatesResourceDictionary.xaml

<!-- TemplatesResourceDictionary.xaml -->
<ResourceDictionary
    x:Class="ExampleNamespace.TemplatesResourceDictionary"
    .....
    xmlns:examplenamespace="using:ExampleNamespace">
    
    <!-- DataTemplate using x:Bind -->
    <DataTemplate x:Key="EmployeeTemplate" x:DataType="examplenamespace:IEmployee">
        <Grid>
            <TextBlock Text="{x:Bind Name}"/>
        </Grid>
    </DataTemplate>
    
    <!-- Style that mixes x:Bind and Binding -->
    <Style x:Key="CustomButtonStyle" TargetType="Button">
        <Setter Property="Background" Value="{Binding ButtonBackgroundBrush}"/>
        <Setter Property="Foreground" Value="{Binding ButtonForegroundBrush}"/>
        <Setter Property="FontSize" Value="16"/>
        <Setter Property="Margin" Value="4"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="Button">
                    <Border x:Name="RootBorder"
                            Background="{TemplateBinding Background}"
                            BorderBrush="{TemplateBinding BorderBrush}"
                            BorderThickness="{TemplateBinding BorderThickness}"
                            CornerRadius="4">
                        <StackPanel Orientation="Horizontal" 
                                    HorizontalAlignment="Center"
                                    VerticalAlignment="Center">
                            <!-- x:Bind to a static property or page-level property -->
                            <Ellipse Width="8" Height="8" 
                                     Fill="{x:Bind DefaultIndicatorBrush}" 
                                     Margin="0,0,8,0"/>
                            <!-- Binding to DataContext -->
                            <ContentPresenter x:Name="ContentPresenter"
                                              Content="{TemplateBinding Content}"
                                              Foreground="{TemplateBinding Foreground}"
                                              FontSize="{TemplateBinding FontSize}"/>
                        </StackPanel>
                        <VisualStateManager.VisualStateGroups>
                            <VisualStateGroup x:Name="CommonStates">
                                <VisualState x:Name="Normal"/>
                                <VisualState x:Name="PointerOver">
                                    <VisualState.Setters>
                                        <!-- Binding to DataContext for hover color -->
                                        <Setter Target="RootBorder.Background" 
                                                Value="{Binding ButtonHoverBrush}"/>
                                    </VisualState.Setters>
                                </VisualState>
                                <VisualState x:Name="Pressed">
                                    <VisualState.Setters>
                                        <!-- x:Bind to a compile-time known resource -->
                                        <Setter Target="RootBorder.Background" 
                                                Value="{x:Bind DefaultPressedBrush}"/>
                                    </VisualState.Setters>
                                </VisualState>
                            </VisualStateGroup>
                        </VisualStateManager.VisualStateGroups>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

TemplatesResourceDictionary.xaml.cs

// TemplatesResourceDictionary.xaml.cs
using Microsoft.UI;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Data;
using Microsoft.UI.Xaml.Media;
 
namespace ExampleNamespace
{
    public partial class TemplatesResourceDictionary
    {
        public TemplatesResourceDictionary()
        {
            InitializeComponent();
        }
        
        // Properties for x:Bind - these are compile-time bound
        public SolidColorBrush DefaultIndicatorBrush { get; } = 
            new SolidColorBrush(Colors.Green);
            
        public SolidColorBrush DefaultPressedBrush { get; } = 
            new SolidColorBrush(Colors.DarkGray);
    }
}

Användning i MainWindow.xaml med en ViewModel som tillhandahåller körningsvärden:

<!-- MainWindow.xaml -->
<Window x:Class="ExampleNamespace.MainWindow"
    ....
    xmlns:examplenamespace="using:ExampleNamespace">

    <Window.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <examplenamespace:TemplatesResourceDictionary/>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Window.Resources>

    <Grid>
        <Grid.DataContext>
            <examplenamespace:ButtonThemeViewModel/>
        </Grid.DataContext>
        
        <StackPanel Margin="20">
            <!-- These buttons use the mixed binding style -->
            <Button Content="Save" Style="{StaticResource CustomButtonStyle}"/>
            <Button Content="Cancel" Style="{StaticResource CustomButtonStyle}"/>
        </StackPanel>
    </Grid>
</Window>

ButtonThemeViewModel.cs (DataContext som tillhandahåller körningsbindningsvärden):

using System.ComponentModel;
using Microsoft.UI;
using Microsoft.UI.Xaml.Media;

namespace ExampleNamespace
{
    public class ButtonThemeViewModel : INotifyPropertyChanged
    {
        private SolidColorBrush _buttonBackgroundBrush = new SolidColorBrush(Colors.LightBlue);
        private SolidColorBrush _buttonForegroundBrush = new SolidColorBrush(Colors.DarkBlue);
        private SolidColorBrush _buttonHoverBrush = new SolidColorBrush(Colors.LightCyan);

        public SolidColorBrush ButtonBackgroundBrush
        {
            get => _buttonBackgroundBrush;
            set
            {
                _buttonBackgroundBrush = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ButtonBackgroundBrush)));
            }
        }

        public SolidColorBrush ButtonForegroundBrush
        {
            get => _buttonForegroundBrush;
            set
            {
                _buttonForegroundBrush = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ButtonForegroundBrush)));
            }
        }

        public SolidColorBrush ButtonHoverBrush
        {
            get => _buttonHoverBrush;
            set
            {
                _buttonHoverBrush = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ButtonHoverBrush)));
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
    }
}

I det här exemplet:

  • {Binding} används för egenskaper som är beroende av DataContext (ButtonBackgroundBrush, ButtonForegroundBrush, ButtonHoverBrush)
  • {x:Bind} används för egenskaper som är kända för kompileringstid och tillhör själva ResourceDictionary (DefaultIndicatorBrush, DefaultPressedBrush)
  • Formatet kan återanvändas och kan tillämpas på valfri knapp
  • Körningstema är möjligt via DataContext och drar fortfarande nytta av {x:Bind} prestanda för statiska element

Händelsebindning och ICommand

{x:Bind} stöder en funktion som kallas händelsebindning. Med den här funktionen kan du ange hanteraren för en händelse med hjälp av en bindning, vilket är ytterligare ett alternativ utöver att hantera händelser med en metod i filen bakom koden. Anta att du har en ListViewDoubleTapped händelsehanterare i din MainWindow klass.

public sealed partial class MainWindow : Window
{
    ...
    public void ListViewDoubleTapped()
    {
        // Handle double-tapped logic
    }
}

Du kan sedan binda en DoubleTapped-händelse i ListView till en metod i MainWindow så här.

<ListView DoubleTapped="{x:Bind ListViewDoubleTapped}" />

Överlagrade metoder kan inte användas för att hantera en händelse med den här tekniken. Om metoden som hanterar händelsen har parametrar måste alla vara tilldelningsbara från typerna av alla händelsens parametrar. I det här fallet ListViewDoubleTapped är inte överbelastad och har inga parametrar (men det skulle fortfarande vara giltigt även om det tog två object parametrar).

Händelsebindningstekniken liknar implementering och användning av kommandon (ett kommando är en egenskap som returnerar ett objekt som implementerar ICommand-gränssnittet ). Både {x:Bind} och {Binding} fungerar med kommandon. Så att du inte behöver implementera kommandomönstret flera gånger kan du använda hjälpklassen DelegateCommand som du hittar i QuizGame UWP-exemplet (i mappen "Common").

Bindning till en samling mappar eller filer

Du kan använda API:erna i namnområdet Windows.Storage för att hämta mapp- och fildata i dina paketerade Windows App SDK-appar. De olika GetFilesAsyncmetoderna , GetFoldersAsyncoch GetItemsAsync returnerar dock inte värden som är lämpliga för bindning till listkontroller. I stället måste du binda till returvärdena för metoderna GetVirtualizedFilesVector, GetVirtualizedFoldersVector och GetVirtualizedItemsVector i klassen FileInformationFactory . Följande kodexempel från UWP-exemplet StorageDataSource och GetVirtualizedFilesVector visar det typiska användningsmönstret. Kom ihåg att deklarera funktionen picturesLibrary i apppaketmanifestet och bekräfta att det finns bilder i biblioteksmappen Bilder.

protected override void OnNavigatedTo(NavigationEventArgs e)
{
    var library = Windows.Storage.KnownFolders.PicturesLibrary;
    var queryOptions = new Windows.Storage.Search.QueryOptions();
    queryOptions.FolderDepth = Windows.Storage.Search.FolderDepth.Deep;
    queryOptions.IndexerOption = Windows.Storage.Search.IndexerOption.UseIndexerWhenAvailable;

    var fileQuery = library.CreateFileQueryWithOptions(queryOptions);

    var fif = new Windows.Storage.BulkAccess.FileInformationFactory(
        fileQuery,
        Windows.Storage.FileProperties.ThumbnailMode.PicturesView,
        190,
        Windows.Storage.FileProperties.ThumbnailOptions.UseCurrentScale,
        false
        );

    var dataSource = fif.GetVirtualizedFilesVector();
    this.PicturesListView.ItemsSource = dataSource;
}

Du använder vanligtvis den här metoden för att skapa en skrivskyddad vy över fil- och mappinformation. Du kan skapa tvåvägsbindningar till fil- och mappegenskaperna, till exempel för att låta användare betygsätta en låt i en musikvy. Ändringar sparas dock inte förrän du anropar lämplig SavePropertiesAsync metod (till exempel MusicProperties.SavePropertiesAsync). Du bör checka in ändringar när objektet förlorar fokus eftersom detta utlöser en markeringsåterställning.

Observera att dubbelriktad bindning med den här tekniken endast fungerar med indexerade platser, till exempel Musik. Du kan avgöra om en plats indexeras genom att anropa metoden FolderInformation.GetIndexedStateAsync .

Observera också att en virtualiserad vektor kan returneras null för vissa objekt innan den fyller i deras värde. Du bör till exempel söka efter innan du använder värdet null för en listkontroll som är bunden till en virtualiserad vektor, eller använd SelectedIndex i stället.

Bindning till data grupperade efter en nyckel

Om du tar en platt samling objekt (böcker, till exempel representeras av en BookSku klass) och du grupperar objekten med hjälp av en gemensam egenskap som en nyckel ( BookSku.AuthorName egenskapen, till exempel) kallas resultatet grupperade data. När du grupperar data är det inte längre en platt samling. Grupperade data är en samling gruppobjekt, där varje gruppobjekt har:

  • en nyckel, och
  • en samling objekt vars egenskap matchar den nyckeln.

Om du vill ta bokexemplet igen resulterar resultatet av att gruppera böckerna efter författarens namn i en samling med författarnamnsgrupper där varje grupp har:

  • en nyckel, som är ett författarens namn, och
  • en samling av de BookSku objekt vars AuthorName egenskap matchar gruppens nyckel.

Om du vill visa en samling binder du objektkällan för en objektkontroll (till exempel ListView eller GridView) direkt till en egenskap som returnerar en samling. Om det är en platt samling objekt behöver du inte göra något speciellt. Men om det är en samling gruppobjekt (som det är när du binder till grupperade data) behöver du tjänsterna för ett mellanliggande objekt som kallas en CollectionViewSource som finns mellan objektkontrollen och bindningskällan. Du binder CollectionViewSource till egenskapen som returnerar grupperade data och binder objektkontrollen till CollectionViewSource. Ett extra värdetillägg av ett CollectionViewSource är att det håller reda på det aktuella objektet, så att du kan hålla fler än ett objekt i synkronisering genom att binda dem alla till samma CollectionViewSource. Du kan också komma åt det aktuella objektet programmatiskt via egenskapen ICollectionView.CurrentItem för objektet som returneras av egenskapen CollectionViewSource.View .

Om du vill aktivera grupperingsanläggningen för en CollectionViewSource anger du IsSourceGrouped till true. Om du också behöver ange egenskapen ItemsPath beror på exakt hur du skapar dina gruppobjekt. Det finns två sätt att skapa ett gruppobjekt: mönstret "is-a-group" och mönstret "has-a-group". I mönstret "is-a-group" härleds gruppobjektet från en samlingstyp (till exempel List<T>), så gruppobjektet är faktiskt själva objektgruppen. Med det här mönstret behöver du inte ange ItemsPath. I mönstret "has-a-group" har gruppobjektet en eller flera egenskaper av en samlingstyp (till exempel List<T>), så gruppen "har en" grupp med objekt i form av en egenskap (eller flera grupper av objekt i form av flera egenskaper). Med det här mönstret måste du ange ItemsPath namnet på egenskapen som innehåller objektgruppen.

Exemplet nedan illustrerar mönstret "has-a-group". Fönsterklassen har en egenskap med namnet DataContext, som returnerar en instans av vår vymodell. CollectionViewSource binder till Authors egenskapen för vymodellen (Authors är samlingen med gruppobjekt) och anger även att det är egenskapen Author.BookSkus som innehåller de grupperade objekten. Slutligen är GridView bundet CollectionViewSourcetill , och dess gruppformat har definierats så att det kan återge objekten i grupper.

<Window.Resources>
    <CollectionViewSource
    x:Name="AuthorHasACollectionOfBookSku"
    Source="{x:Bind ViewModel.Authors}"
    IsSourceGrouped="true"
    ItemsPath="BookSkus"/>
</Window.Resources>
...
<GridView
ItemsSource="{x:Bind AuthorHasACollectionOfBookSku}" ...>
    <GridView.GroupStyle>
        <GroupStyle
            HeaderTemplate="{StaticResource AuthorGroupHeaderTemplateWide}" ... />
    </GridView.GroupStyle>
</GridView>

Du kan implementera mönstret "is-a-group" på något av två sätt. Ett sätt är att skapa en egen gruppklass. Härled klassen från List<T> (där T är typen av objekt). Till exempel public class Author : List<BookSku>. Det andra sättet är att använda ett LINQ-uttryck för att dynamiskt skapa gruppobjekt (och en gruppklass) från liknande egenskapsvärden för BookSku-objekten . Den här metoden – att endast underhålla en platt lista över objekt och gruppera dem i farten – är typisk för en app som kommer åt data från en molntjänst. Du får flexibiliteten att gruppera böcker efter författare eller genre (till exempel) utan att behöva särskilda gruppklasser som Författare och Genre.

Exemplet nedan illustrerar "is-a-group"-mönstret med LINQ. Den här gången grupperar vi böcker efter genre, som visas med genrenamnet i grupprubrikerna. Detta indikeras av egenskapssökvägen "Nyckel" som referens till gruppnyckelvärdet .

using System.Linq;
...
private IOrderedEnumerable<IGrouping<string, BookSku>> genres;

public IOrderedEnumerable<IGrouping<string, BookSku>> Genres
{
    get
    {
        if (genres == null)
        {
            genres = from book in bookSkus
                     group book by book.genre into grp
                     orderby grp.Key
                     select grp;
        }
        return genres;
    }
}

Kom ihåg att när du använder {x:Bind} med datamallar måste vi ange vilken typ som ska bindas till genom att ange ett x:DataType värde. Om typen är allmän kan vi inte uttrycka den i markering, så vi måste använda {Binding} i stället i mallen för gruppformatrubriken.

    <Grid.Resources>
        <CollectionViewSource x:Name="GenreIsACollectionOfBookSku"
        Source="{x:Bind Genres}"
        IsSourceGrouped="true"/>
    </Grid.Resources>
    <GridView ItemsSource="{x:Bind GenreIsACollectionOfBookSku}">
        <GridView.ItemTemplate x:DataType="local:BookTemplate">
            <DataTemplate>
                <TextBlock Text="{x:Bind Title}"/>
            </DataTemplate>
        </GridView.ItemTemplate>
        <GridView.GroupStyle>
            <GroupStyle>
                <GroupStyle.HeaderTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding Key}"/>
                    </DataTemplate>
                </GroupStyle.HeaderTemplate>
            </GroupStyle>
        </GridView.GroupStyle>
    </GridView>

En SemanticZoom-kontroll är ett bra sätt för användarna att visa och navigera i grupperade data. Exempelappen Bookstore2 UWP visar hur du SemanticZoomanvänder . I appen kan du visa en lista över böcker grupperade efter författare (den inzoomade vyn) eller så kan du zooma ut för att se en snabblista med författare (den utzoomade vyn). Hopplistan ger mycket snabbare navigering än att bläddra igenom listan över böcker. De inzoomade och utzoomade vyerna är faktiskt ListView eller GridView kontroller som är bundna till samma CollectionViewSource.

En bild av en SemanticZoom

När du binder till hierarkiska data, till exempel underkategorier inom kategorier, kan du välja att visa hierarkiska nivåer i användargränssnittet med en serie objektkontroller. En markering i en objektkontroll avgör innehållet i efterföljande objektkontroller. Du kan hålla listorna synkroniserade genom att binda varje lista till sin egen CollectionViewSource och binda CollectionViewSource samman instanserna i en kedja. Detta kallas för en huvud-/informationsvy (eller lista/information). Mer information finns i Så här binder du till hierarkiska data och skapar en huvud-/informationsvy.

Diagnostisera och felsöka problem med databindning

Bindningsmarkeringen innehåller namnen på egenskaperna (och för C#, ibland fält och metoder). Så när du byter namn på en egenskap måste du också ändra alla bindningar som refererar till den. Om du glömmer att göra det leder det till ett typiskt exempel på en databindningsfel, och din app kompilerar inte eller kommer inte att köras korrekt.

Bindningsobjekten som skapats av {x:Bind} och {Binding} är till stor del funktionellt likvärdiga. Men {x:Bind} har typinformation för bindningskällan och genererar källkod vid kompileringstid. Med {x:Bind} får du samma typ av problemidentifiering som du får med resten av koden. Det inkluderar kompileringstidsverifiering av dina bindningsuttryck och felsökning genom att ange brytpunkter i källkoden som genereras som partiell klass för sidan. Dessa klasser finns i filerna i mappen obj med namn som (för C#) <view name>.g.cs). Om du har problem med en bindning aktiverar du Bryt vid ohanterade undantag i Microsoft Visual Studio-felsökningsprogrammet. Felsökningsprogrammet bryter körningen vid den tidpunkten och du kan sedan felsöka vad som har gått fel. Koden som genereras av {x:Bind} följer samma mönster för varje del av grafen med bindning av källnoder, och du kan använda informationen i fönstret Anropa stack för att fastställa sekvensen av anrop som ledde fram till problemet.

{Binding} har inte typinformation för bindningskällan. Men när du kör din app med felsökningsprogrammet kopplat visas eventuella bindningsfel i fönstret Utdata - och XAML-bindningsfel i Visual Studio. Mer information om felsökning av bindningsfel i Visual Studio finns i XAML-databindningsdiagnostik.

Skapa bindningar i kod

Anmärkning

Det här avsnittet gäller endast för {Binding}, eftersom du inte kan skapa {x:Bind} -bindningar i kod. Vissa av fördelarna med {x:Bind} kan dock uppnås med DependencyObject.RegisterPropertyChangedCallback, som gör att du kan registrera dig för ändringsmeddelanden för alla beroendeegenskaper.

Du kan också ansluta gränssnittselement till data med hjälp av procedurkod i stället för XAML. Det gör du genom att skapa ett nytt bindningsobjekt , ange lämpliga egenskaper och sedan anropa FrameworkElement.SetBinding eller BindingOperations.SetBinding. Att skapa bindningar programmatiskt är användbart när du vill välja bindningsegenskapsvärdena vid körning eller dela en enda bindning mellan flera kontroller. Observera dock att du inte kan ändra bindningsegenskapsvärdena när du anropar SetBinding.

I följande exempel visas hur du implementerar en bindning i kod.

<TextBox x:Name="MyTextBox" Text="Text"/>
// Create an instance of the MyColors class 
// that implements INotifyPropertyChanged.
var textcolor = new MyColors();

// Brush1 is set to be a SolidColorBrush with the value Red.
textcolor.Brush1 = new SolidColorBrush(Colors.Red);

// Set the DataContext of the TextBox MyTextBox.
MyTextBox.DataContext = textcolor;

// Create the binding and associate it with the text box.
var binding = new Binding { Path = new PropertyPath("Brush1") };
MyTextBox.SetBinding(TextBox.ForegroundProperty, binding);

Funktionsjämförelse för {x:Bind} och {Binding}

Egenskap {x:Bind} jämfört med {Binding} Noteringar
Sökvägen är standardegenskapen {x:Bind a.b.c}
-
{Binding a.b.c}
Sökvägsegenskap {x:Bind Path=a.b.c}
-
{Binding Path=a.b.c}
x:Bind I Pathrotas i fönstret som standard, inte i DataContext.
Indexer {x:Bind Groups[2].Title}
-
{Binding Groups[2].Title}
Binder till det angivna objektet i samlingen. Endast heltalsbaserade index stöds.
Anslutna egenskaper {x:Bind Button22.(Grid.Row)}
-
{Binding Button22.(Grid.Row)}
Anslutna egenskaper anges med parenteser. Om egenskapen inte deklareras i ett XAML-namnområde prefixar du den med ett XML-namnområde, som ska mappas till ett kodnamnområde i dokumentets huvud.
Gjutning {x:Bind groups[0].(data:SampleDataGroup.Title)}
-
Behövs inte för {Binding}.
Casts anges med parenteser. Om egenskapen inte deklareras i ett XAML-namnområde prefixar du den med ett XML-namnområde, som ska mappas till ett kodnamnområde i dokumentets huvud.
Omvandlare {x:Bind IsShown, Converter={StaticResource BoolToVisibility}}
-
{Binding IsShown, Converter={StaticResource BoolToVisibility}}
Konverterare måste deklareras i roten för Window/Control/ResourceDictionary eller i App.xaml.
ConverterParameter, ConverterLanguage {x:Bind IsShown, Converter={StaticResource BoolToVisibility}, ConverterParameter=One, ConverterLanguage=fr-fr}
-
{Binding IsShown, Converter={StaticResource BoolToVisibility}, ConverterParameter=One, ConverterLanguage=fr-fr}
Konverterare måste deklareras i roten för Window/Control/ResourceDictionary eller i App.xaml.
TargetNullValue {x:Bind Name, TargetNullValue=0}
-
{Binding Name, TargetNullValue=0}
Används när bladet i bindningsuttrycket är null. Använd enkla citattecken för ett strängvärde.
FallbackValue {x:Bind Name, FallbackValue='empty'}
-
{Binding Name, FallbackValue='empty'}
Används när någon del av sökvägen för bindningen (förutom bladet) är null.
ElementName {x:Bind slider1.Value}
-
{Binding Value, ElementName=slider1}
När {x:Bind} du är bindning till ett fält Path är det rotat i fönstret som standard, så att alla namngivna element kan nås via dess fält.
RelativeSource: Själv <Rectangle x:Name="rect1" Width="200" Height="{x:Bind rect1.Width}" ... />
-
<Rectangle Width="200" Height="{Binding Width, RelativeSource={RelativeSource Self}}" ... />
Med {x:Bind}namnger du elementet och använder dess namn i Path.
RelativeSource: TemplatedParent Behövs inte för {x:Bind}
-
{Binding <path>, RelativeSource={RelativeSource TemplatedParent}}
Med {x:Bind}anger on TargetTypeControlTemplate bindning till mallens överordnade. För {Binding}kan vanlig mallbindning användas i kontrollmallar för de flesta användningsområden. Men använd TemplatedParent där du behöver använda en konverterare eller en dubbelriktad bindning.
Källa Behövs inte för {x:Bind}
-
<ListView ItemsSource="{Binding Orders, Source={StaticResource MyData}}"/>
Du {x:Bind} kan använda det namngivna elementet direkt genom att använda en egenskap eller en statisk sökväg.
Mode {x:Bind Name, Mode=OneWay}
-
{Binding Name, Mode=TwoWay}
Mode kan vara OneTime, OneWayeller TwoWay. {x:Bind} standardvärdet är OneTime; {Binding} standardvärdet OneWay.
UpdateSourceTrigger {x:Bind Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}
-
{Binding UpdateSourceTrigger=PropertyChanged}
UpdateSourceTrigger kan vara Default, LostFocuseller PropertyChanged. {x:Bind} stöder UpdateSourceTrigger=Explicitinte . {x:Bind} använder PropertyChanged beteende för alla fall utom TextBox.Text, där det använder LostFocus beteende.

Se även