Not
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Med databindning i WinUI-appar kan du effektivt ansluta kontroller till datakällor. Lär dig hur du binder en kontroll till ett enskilt objekt eller en samling objekt, kontrollerar objektrendering, implementerar informationsvyer och formaterar data för visning. Mer information finns i Databindning på djupet.
Förutsättningar
Det här avsnittet förutsätter att du vet hur du skapar en grundläggande WinUI-app med Windows App SDK. Anvisningar om hur du skapar din första WinUI-app finns i Skapa en WinUI-app.
Skapa projektet
Skapa ett nytt tomt WinUI-program, paketerat C#-projekt. Ge den namnet "Snabbstart".
Binda till ett enskilt objekt
Varje bindning består av ett bindningsmål och en bindningskälla. Vanligtvis är målet en egenskap för en kontroll eller ett annat gränssnittselement, och källan är en egenskap för en klassinstans (en datamodell eller en vymodell). Det här exemplet visar hur du binder en kontroll till ett enda objekt. Målet är att rikta in sig på egenskapen Text hos en TextBlock. Källan är en instans av en enkel klass med namnet Recording som representerar en ljudinspelning. Låt oss titta på klassen först.
Lägg till en ny klass i projektet och ge klassen namnet Recording.
namespace Quickstart
{
public class Recording
{
public string ArtistName { get; set; }
public string CompositionName { get; set; }
public DateTime ReleaseDateTime { get; set; }
public Recording()
{
ArtistName = "Wolfgang Amadeus Mozart";
CompositionName = "Andante in C for Piano";
ReleaseDateTime = new DateTime(1761, 1, 1);
}
public string OneLineSummary
{
get
{
return $"{CompositionName} by {ArtistName}, released: "
+ ReleaseDateTime.ToString("d");
}
}
}
public class RecordingViewModel
{
private Recording defaultRecording = new();
public Recording DefaultRecording { get { return defaultRecording; } }
}
}
Exponera sedan bindningskällklassen från klassen som representerar ditt markeringsfönster. Lägg till en egenskap av typen RecordingViewModeli MainWindow.xaml.cs.
namespace Quickstart
{
public sealed partial class MainWindow : Window
{
public MainWindow()
{
this.InitializeComponent();
}
public RecordingViewModel ViewModel{ get; } = new RecordingViewModel();
}
}
Den sista delen är att binda en TextBlock till egenskapen ViewModel.DefaultRecording.OneLineSummary.
<Window x:Class="Quickstart.MainWindow" ... >
<Grid>
<TextBlock Text="{x:Bind ViewModel.DefaultRecording.OneLineSummary}"
HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Grid>
</Window>
Här är resultatet.
Binda till en samling objekt
Ett vanligt scenario är att binda till en samling affärsobjekt. I C# använder du den generiska klassen ObservableCollection<T> för databindning. Den implementerar gränssnittet INotifyCollectionChanged , som tillhandahåller ändringsmeddelanden till bindningar när objekt läggs till eller tas bort. Men på grund av ett känt fel i WinUI release-läge med .NET 8 och senare kan du behöva använda en Lista<T> i vissa scenarier, särskilt om samlingen är statisk och inte ändras efter initialisering. Om användargränssnittet behöver uppdateras när samlingen ändras vid körning använder du ObservableCollection<T>. Om du bara behöver visa en fast uppsättning objekt List<T> räcker det. Om du vill att dina bundna kontroller ska uppdateras med ändringar i egenskaperna för objekt i samlingen bör dessa objekt dessutom implementera INotifyPropertyChanged. Mer information finns i Databindning på djupet.
Anteckning
Med hjälp av List<T>får du kanske inte ändringsmeddelanden för samlingsändringar. Om du behöver svara på ändringar bör du överväga att använda ObservableCollection<T>. I det här exemplet behöver du inte svara på samlingsändringar, så List<T> det räcker.
I följande exempel binder en ListView till en samling Recording objekt. Lägg först till samlingen i vymodellen. Lägg till dessa nya medlemmar i RecordingViewModel klassen.
public class RecordingViewModel
{
...
private List<Recording> recordings = new();
public List<Recording> Recordings{ get{ return recordings; } }
public RecordingViewModel()
{
recordings.Add(new Recording(){ ArtistName = "Johann Sebastian Bach",
CompositionName = "Mass in B minor", ReleaseDateTime = new DateTime(1748, 7, 8) });
recordings.Add(new Recording(){ ArtistName = "Ludwig van Beethoven",
CompositionName = "Third Symphony", ReleaseDateTime = new DateTime(1805, 2, 11) });
recordings.Add(new Recording(){ ArtistName = "George Frideric Handel",
CompositionName = "Serse", ReleaseDateTime = new DateTime(1737, 12, 3) });
}
}
Bind sedan en ListView till egenskapen ViewModel.Recordings .
<Window x:Class="Quickstart.MainWindow" ... >
<Grid>
<ListView ItemsSource="{x:Bind ViewModel.Recordings}"
HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Grid>
</Window>
Du har ännu inte angett någon datamall för Recording klassen, så det bästa UI-ramverket kan göra är att anropa ToString för varje objekt i ListView. Standardimplementeringen av ToString returnerar typnamnet.
För att åtgärda det här problemet kan du antingen åsidosätta ToString för att returnera värdet OneLineSummaryför , eller så kan du ange en datamall. Alternativet datamall är en vanligare och mer flexibel lösning. Du anger en datamall med hjälp av egenskapen ContentTemplate för en innehållskontroll eller egenskapen ItemTemplate för en objektkontroll. Här är två sätt att utforma en datamall för Recording tillsammans med en bild av resultatet.
<ListView ItemsSource="{x:Bind ViewModel.Recordings}"
HorizontalAlignment="Center" VerticalAlignment="Center">
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:Recording">
<TextBlock Text="{x:Bind OneLineSummary}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<ListView ItemsSource="{x:Bind ViewModel.Recordings}"
HorizontalAlignment="Center" VerticalAlignment="Center">
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:Recording">
<StackPanel Orientation="Horizontal" Margin="6">
<SymbolIcon Symbol="Audio" Margin="0,0,12,0"/>
<StackPanel>
<TextBlock Text="{x:Bind ArtistName}" FontWeight="Bold"/>
<TextBlock Text="{x:Bind CompositionName}"/>
</StackPanel>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Mer information om XAML-syntax finns i Skapa ett användargränssnitt med XAML-. Mer information om kontrolllayout finns i Definiera layouter med XAML-.
Lägga till en informationsvy
Du kan välja att visa all information om Recording objekt i ListView objekt. Men det tillvägagångssättet tar upp mycket utrymme. I stället kan du visa tillräckligt med data i objektet för att identifiera det. När användaren gör en markering kan du visa all information om det markerade objektet i ett separat användargränssnitt som kallas för informationsvyn. Det här arrangemanget kallas även för en huvud-/detaljvy eller en list-/detaljvy.
Du kan implementera det här arrangemanget på två sätt. Du kan binda informationsvyn till egenskapen SelectedItem för ListView-. Eller så kan du använda en CollectionViewSource. I det här fallet binder du både ListView och detaljvyn till CollectionViewSource. Den här metoden tar hand om det markerade objektet åt dig. Båda teknikerna visas i följande avsnitt och båda ger samma resultat (visas i bilden).
Anteckning
Hittills i det här avsnittet har du bara använt markeringstillägget {x:Bind}. Men båda teknikerna som visas i följande avsnitt kräver det mer flexibla (men mindre högpresterande) {Binding}-markeringstillägget.
Först, här är tekniken SelectedItem. För ett C#-program är den enda ändring som krävs i märkningen.
<Window x:Class="Quickstart.MainWindow" ... >
<Grid>
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<ListView x:Name="recordingsListView" ItemsSource="{x:Bind ViewModel.Recordings}">
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:Recording">
<StackPanel Orientation="Horizontal" Margin="6">
<SymbolIcon Symbol="Audio" Margin="0,0,12,0"/>
<StackPanel>
<TextBlock Text="{x:Bind CompositionName}"/>
</StackPanel>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<StackPanel DataContext="{Binding SelectedItem, ElementName=recordingsListView}"
Margin="0,24,0,0">
<TextBlock Text="{Binding ArtistName}"/>
<TextBlock Text="{Binding CompositionName}"/>
<TextBlock Text="{Binding ReleaseDateTime}"/>
</StackPanel>
</StackPanel>
</Grid>
</Window>
För tekniken CollectionViewSource lägger du först till en CollectionViewSource som en resurs på den översta nivån Grid.
<Grid.Resources>
<CollectionViewSource x:Name="RecordingsCollection" Source="{x:Bind ViewModel.Recordings}"/>
</Grid.Resources>
Anteckning
Klassen Window i WinUI har ingen egenskap för Resources. Du kan lägga till CollectionViewSource till det översta Grid -elementet (eller något annat överordnat gränssnittselement som StackPanel) i stället. Om du arbetar inom en Pagekan du lägga till CollectionViewSource i Page.Resources.
Justera sedan bindningarna i ListView (som inte längre behöver namnges) och på informationsvyn för att använda CollectionViewSource. Genom att binda informationsvyn direkt till CollectionViewSourceantyder du att du vill binda till det aktuella objektet i bindningar där sökvägen inte kan hittas i själva samlingen. Du behöver inte ange egenskapen CurrentItem som sökväg för bindningen, även om du kan göra det om det finns tvetydigheter.
...
<ListView ItemsSource="{Binding Source={StaticResource RecordingsCollection}}">
...
<StackPanel DataContext="{Binding Source={StaticResource RecordingsCollection}}" ...>
...
Och här är det identiska resultatet i varje fall.
Formatera eller konvertera datavärden för visning
Återgivningen ovan har ett problem. Egenskapen ReleaseDateTime är inte bara ett datum, det är en DateTime. Därför visas den med mer precision än du behöver. En lösning är att lägga till en strängegenskap i klassen Recording som returnerar motsvarigheten till ReleaseDateTime.ToString("d"). Att namnge egenskapen ReleaseDate anger att den returnerar ett datum och inte ett datum och en tid. Att namnge den ReleaseDateAsString ytterligare anger att den returnerar en sträng.
En mer flexibel lösning är att använda en värdekonverterare. Här är ett exempel på hur du skapar en egen värdekonverterare. Lägg till följande kod i din Recording.cs källkodsfil.
public class StringFormatter : Microsoft.UI.Xaml.Data.IValueConverter
{
// This converts the value object to the string to display.
// This will work with most simple types.
public object Convert(object value, Type targetType,
object parameter, string language)
{
// Retrieve the format string and use it to format the value.
string formatString = parameter as string;
if (!string.IsNullOrEmpty(formatString))
{
return string.Format(formatString, value);
}
// If the format string is null or empty, simply
// call ToString() on the value.
return value.ToString();
}
// No need to implement converting back on a one-way binding
public object ConvertBack(object value, Type targetType,
object parameter, string language)
{
throw new NotImplementedException();
}
}
Nu kan du lägga till en instans av StringFormatter som en resurs och använda den i bindningen av TextBlock som visar egenskapen ReleaseDateTime.
<Grid.Resources>
...
<local:StringFormatter x:Key="StringFormatterValueConverter"/>
</Grid.Resources>
...
<TextBlock Text="{Binding ReleaseDateTime,
Converter={StaticResource StringFormatterValueConverter},
ConverterParameter=Released: \{0:d\}}"/>
...
Som du ser skickar markeringen för formateringsflexitet en formatsträng till konverteraren med hjälp av konverterarens parameter. I kodexemplet som visas i det här avsnittet använder C#-värdekonverteraren den parametern.
Här är resultatet.
Skillnader mellan Bindning och "x:Bind"
När du arbetar med databindning i WinUI-appar kan du stöta på två primära bindningsmekanismer: Binding och x:Bind. Båda tjänar syftet med att ansluta gränssnittselement till datakällor, men de har distinkta skillnader:
-
x:Bind: Erbjuder kompileringstidskontroll, bättre prestanda och är starkt skrivet. Det är idealiskt för scenarier där du känner till datastrukturen vid kompileringstiden. -
Binding: Ger körningsutvärdering och är mer flexibelt för dynamiska scenarier, till exempel när datastrukturen inte är känd vid kompileringstillfället.
Scenarier som inte stöds av x:Bind
Även om x:Bind det är kraftfullt kan du inte använda det i vissa scenarier:
-
Dynamiska datastrukturer: Om datastrukturen inte är känd vid kompileringstillfället kan du inte använda
x:Bind. -
Bindning mellan element:
x:Bindstöder inte bindning direkt mellan två gränssnittselement. -
Bindning till
DataContext:x:Bindärver inte automatiskt ettDataContext-element som är överordnat. -
Dubbelriktade bindningar med
Mode=TwoWay: När det stödsx:Bindkräver explicit implementering avINotifyPropertyChangedför alla egenskaper som du vill att användargränssnittet ska uppdatera när källan ändras, oavsett om du använder enkelriktad eller dubbelriktad bindning. Den viktigaste skillnaden med dubbelriktade bindningar är att ändringar också flödar från användargränssnittet tillbaka till källan.
Praktiska exempel och en djupare förståelse för när var och en ska användas finns i följande avsnitt:
Relaterat innehåll
Windows developer