Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
Met gegevensbinding in WinUI-apps kunt u besturingselementen efficiënt verbinden met gegevensbronnen. Informatie over het binden van een besturingselement aan één item of een verzameling items, het weergeven van besturingsitems, het implementeren van detailweergaven en het opmaken van gegevens voor weergave. Zie Gegevensbinding uitgebreid voor meer informatie.
Voorwaarden
In dit onderwerp wordt ervan uitgegaan dat u weet hoe u een eenvoudige WinUI-app maakt met Windows App SDK. Zie Een WinUI-app maken voor instructies voor het maken van uw eerste WinUI-app.
Het project maken
Maak een nieuw WinUI Blank App, verpakt C#-project. Geef deze de naam 'Quickstart'.
Binden aan één item
Elke binding bestaat uit een bindingsdoel en een bindingsbron. Het doel is doorgaans een eigenschap van een besturingselement of een ander UI-element en de bron is een eigenschap van een klasse-exemplaar (een gegevensmodel of een weergavemodel). In dit voorbeeld ziet u hoe u een besturingselement koppelt aan één item. Het doel is de Text eigenschap van een TextBlock. De bron is een exemplaar van een eenvoudige klasse met de naam Recording die een audio-opname vertegenwoordigt. Laten we eerst eens kijken naar de klas.
Voeg een nieuwe klasse toe aan uw project en geef de klasse een naam 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; } }
}
}
Maak vervolgens de bindingsbronklasse beschikbaar vanuit de klasse die het venster met markeringen vertegenwoordigt. Voeg een eigenschap van het type RecordingViewModel toe aan MainWindow.xaml.cs.
namespace Quickstart
{
public sealed partial class MainWindow : Window
{
public MainWindow()
{
this.InitializeComponent();
}
public RecordingViewModel ViewModel{ get; } = new RecordingViewModel();
}
}
Het laatste stuk is het binden van een TextBlock aan de eigenschap ViewModel.DefaultRecording.OneLineSummary.
<Window x:Class="Quickstart.MainWindow" ... >
<Grid>
<TextBlock Text="{x:Bind ViewModel.DefaultRecording.OneLineSummary}"
HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Grid>
</Window>
Dit is het resultaat.
Binden aan een verzameling items
Een veelvoorkomend scenario is het binden aan een verzameling zakelijke objecten. Gebruik in C# de algemene klasse ObservableCollection<T> voor gegevensbinding. Hiermee wordt de interface INotifyCollectionChanged geïmplementeerd, die wijzigingsmeldingen aan bindingen biedt wanneer items worden toegevoegd of verwijderd. Vanwege een bekende winUI-releasemodusfout met .NET 8 en hoger moet u in sommige scenario's mogelijk een Lijst<T> gebruiken, met name als uw verzameling statisch is en niet verandert na de initialisatie. Als uw gebruikersinterface moet worden bijgewerkt wanneer de verzameling tijdens runtime wordt gewijzigd, gebruikt u ObservableCollection<T>. Als u alleen een vaste set items hoeft weer te geven, List<T> is voldoende. Als u wilt dat uw gebonden besturingselementen worden bijgewerkt met wijzigingen in eigenschappen van objecten in de verzameling, moeten deze objecten INotifyPropertyChanged implementeren. Voor meer informatie, zie Gegevensbinding in detail.
Notitie
Als u dit gebruikt List<T>, ontvangt u mogelijk geen wijzigingsmeldingen voor verzamelingswijzigingen. Als u op wijzigingen wilt reageren, overweeg dan om ObservableCollection<T> te gebruiken. In dit voorbeeld hoeft u niet te reageren op wijzigingen in verzamelingen. Dit is dus List<T> voldoende.
In het volgende voorbeeld wordt een ListView gekoppeld aan een verzameling Recording objecten. Voeg eerst de verzameling toe aan uw weergavemodel. Voeg deze nieuwe leden toe aan de RecordingViewModel klas.
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 vervolgens een ListView aan de ViewModel.Recordings eigenschap.
<Window x:Class="Quickstart.MainWindow" ... >
<Grid>
<ListView ItemsSource="{x:Bind ViewModel.Recordings}"
HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Grid>
</Window>
U hebt nog geen gegevenssjabloon voor de Recording klasse opgegeven, dus het beste dat het UI-framework kan doen, is ToString aanroepen voor elk item in ListView. De standaard implementatie van ToString retourneert de typenaam.
U kunt dit probleem oplossen door ToString te overschrijven zodat het de waarde van OneLineSummary teruggeeft, of u kunt een gegevenssjabloon bieden. De optie voor gegevenssjablonen is een meer algemene en flexibele oplossing. U geeft een gegevenssjabloon op met behulp van de eigenschap ContentTemplate van een inhoudsbesturingselement of de eigenschap ItemTemplate van een itembesturingselement. Hier volgen twee manieren waarop u een gegevenssjabloon kunt Recording ontwerpen, samen met een afbeelding van het resultaat.
<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>
Zie Een gebruikersinterface maken met XAML-voor meer informatie over de syntaxis van XAML. Zie Indelingen definiëren met XAML-voor meer informatie over de besturingselementindeling.
Een detailweergave toevoegen
U kunt ervoor kiezen om alle details van Recording objecten weer te geven in ListView items. Maar die benadering neemt veel ruimte in beslag. In plaats daarvan kunt u voldoende gegevens in het item weergeven om het te identificeren. Wanneer de gebruiker een selectie maakt, kunt u alle details van het geselecteerde item weergeven in een afzonderlijk onderdeel van de gebruikersinterface, ook wel de detailweergave genoemd. Deze rangschikking wordt ook wel een master-/detailweergave of een lijst-/detailweergave genoemd.
U kunt deze regeling op twee manieren implementeren. U kunt de detailweergave binden aan de eigenschap SelectedItem van de ListView-. U kunt ook een CollectionViewSource gebruiken. In dit geval verbindt u zowel de ListView als de detailweergave met de CollectionViewSource. Deze aanpak zorgt voor het momenteel geselecteerde item voor u. Beide technieken worden weergegeven in de volgende secties en ze geven beide dezelfde resultaten (weergegeven in de afbeelding).
Notitie
Tot nu toe in dit onderwerp hebt u alleen de markeringsextensie {x:Bind} gebruikt. Maar voor beide technieken die in de volgende secties worden weergegeven, is de meer flexibele (maar minder presterende) {Binding}-markeringsextensie vereist.
Hier is eerst de SelectedItem techniek. Voor een C#-toepassing is de enige wijziging die nodig is voor de markering.
<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>
Voeg voor de techniek CollectionViewSource eerst een CollectionViewSource toe als resource van de Gridop het hoogste niveau.
<Grid.Resources>
<CollectionViewSource x:Name="RecordingsCollection" Source="{x:Bind ViewModel.Recordings}"/>
</Grid.Resources>
Notitie
De klasse Window in WinUI heeft geen eigenschap Resources. In plaats daarvan kunt u de CollectionViewSource toevoegen aan het bovenliggende Grid-element (of een ander bovenliggend UI-element, zoals StackPanel). Als u in een Pagewerkt, kunt u de CollectionViewSource toevoegen aan de Page.Resources.
Pas vervolgens de bindingen in de ListView aan (die niet langer een naam hoeven te hebben) en in de detailweergave om de CollectionViewSource te gebruiken. Door de detailweergave rechtstreeks aan de CollectionViewSourceweergave te koppelen, impliceert u dat u het huidige item wilt binden in bindingen waar het pad niet kan worden gevonden in de verzameling zelf. U hoeft de eigenschap CurrentItem niet op te geven als het pad voor de binding, maar dat kunt u doen als er sprake is van dubbelzinnigheid.
...
<ListView ItemsSource="{Binding Source={StaticResource RecordingsCollection}}">
...
<StackPanel DataContext="{Binding Source={StaticResource RecordingsCollection}}" ...>
...
En dit is het identieke resultaat in elk geval.
Gegevenswaarden opmaken of converteren voor weergave
De bovenstaande rendering heeft een probleem. De ReleaseDateTime eigenschap is niet alleen een datum; het is een datum/tijd. Het wordt dus met meer precisie weergegeven dan u nodig hebt. Een oplossing is het toevoegen van een tekenreekseigenschap aan de Recording-klasse die het equivalent van ReleaseDateTime.ToString("d")retourneert. Als u deze eigenschap ReleaseDate een naam geeft, wordt aangegeven dat deze een datum retourneert en geen datum en tijd. De naam duidt verder aan dat er een string wordt geretourneerd.
Een flexibelere oplossing is het gebruik van een waardeconversieprogramma. Hier volgt een voorbeeld van het ontwerpen van uw eigen waardeconversieprogramma. Voeg de volgende code toe aan uw Recording.cs broncodebestand.
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 kunt u een instantie van StringFormatter als bron toevoegen en deze gebruiken in de binding van de TextBlock, die de eigenschap ReleaseDateTime weergeeft.
<Grid.Resources>
...
<local:StringFormatter x:Key="StringFormatterValueConverter"/>
</Grid.Resources>
...
<TextBlock Text="{Binding ReleaseDateTime,
Converter={StaticResource StringFormatterValueConverter},
ConverterParameter=Released: \{0:d\}}"/>
...
Zoals u kunt zien, wordt voor flexibele opmaak een opmaaktekenreeks via de omzetterparameter doorgegeven aan de omzetter. In het codevoorbeeld dat in dit onderwerp wordt weergegeven, maakt het C#-waardeconversieprogramma gebruik van die parameter.
Dit is het resultaat.
Verschillen tussen binding en x:Bind
Wanneer u werkt met gegevensbinding in WinUI-apps, kunt u twee primaire bindingsmechanismen tegenkomen: Binding en x:Bind. Hoewel beide het doel hebben om UI-elementen te verbinden met gegevensbronnen, hebben ze verschillende verschillen:
-
x:Bind: Biedt controle tijdens compilatie, betere prestaties en is sterk getypeerd. Het is ideaal voor scenario's waarin u de gegevensstructuur tijdens het compileren kent. -
Binding: Biedt runtime-evaluatie en is flexibeler voor dynamische scenario's, zoals wanneer de gegevensstructuur niet bekend is tijdens het compileren.
Scenario's die niet worden ondersteund door x:Bind
Hoewel x:Bind dit krachtig is, kunt u deze niet gebruiken in bepaalde scenario's:
-
Dynamische gegevensstructuren: als de gegevensstructuur niet bekend is tijdens het compileren, kunt u deze niet gebruiken
x:Bind. -
Element-naar-element-binding:
x:Bindbiedt geen ondersteuning voor binding rechtstreeks tussen twee UI-elementen. -
Binden aan een
DataContext:x:Binderf niet automatisch deDataContextvan een bovenliggend element. - Bindingen in twee richtingen met
Mode=TwoWay: Hoewel ondersteund, vereistx:Bindeen expliciete implementatie vanINotifyPropertyChangedvoor elke eigenschap waarvan u wilt dat de UI bijwerkt wanneer de bron wijzigt, ongeacht of er gebruik wordt gemaakt van een eenrichtings- of tweerichtingsbinding. Het belangrijkste verschil met bindingen in twee richtingen is dat wijzigingen ook van de gebruikersinterface naar de bron stromen.
Zie de volgende onderwerpen voor praktische voorbeelden en een dieper inzicht in wanneer u deze kunt gebruiken:
Verwante inhoud
Windows developer