Übersicht über Windows-Datenbindung
In diesem Thema erfahren Sie, wie Sie ein Steuerelement (oder ein anderes UI-Element) an ein einzelnes Element binden oder ein Elementsteuerelement an eine Sammlung von Elementen in einer Windows App SDK-App binden. Darüber hinaus zeigen wir, wie sie das Rendern von Elementen steuern, eine Detailansicht basierend auf einer Auswahl implementieren und Daten für die Anzeige konvertieren. Ausführlichere Informationen finden Sie unter Datenbindung im Detail.
Voraussetzungen
In diesem Thema wird davon ausgegangen, dass Sie wissen, wie Sie eine einfache Windows App SDK-App erstellen. Anweisungen zum Erstellen Ihrer ersten Windows App SDK-App finden Sie unter Erstellen Ihres ersten WinUI 3 (Windows App SDK)-Projekts.
Projekt erstellen
Erstellen Sie ein neues C#-Projekt vom Typ Leere App, Gepackt (WinUI 3 in Desktop). Nennen Sie ihn "Schnellstart".
Binden an ein einzelnes Element
Jede Bindung besteht aus einem Bindungsziel und einer Bindungsquelle. In der Regel ist das Ziel eine Eigenschaft eines Steuerelements oder eines anderen UI-Elements, und die Quelle ist eine Eigenschaft einer Klasseninstanz (ein Datenmodell oder ein Ansichtsmodell). In diesem Beispiel wird gezeigt, wie ein Steuerelement an ein einzelnes Element gebunden wird. Das Ziel ist die Eigenschaft Text
eines Textblocks (TextBlock
). Die Quelle ist eine Instanz einer einfachen Klasse namens Recording
, die eine Audioaufzeichnung darstellt. Befassen wir uns zuerst mit der Klasse.
Fügen Sie Ihrem Projekt eine neue Klasse hinzu, und nennen Sie die Klasse 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 Recording();
public Recording DefaultRecording { get { return defaultRecording; } }
}
}
Machen Sie als Nächstes die Bindungsquellklasse aus der Klasse verfügbar, die Ihr Markupfenster darstellt. Fügen Sie hierzu eine Eigenschaft vom Typ RecordingViewModel
zu MainWindow.xaml.cs hinzu.
namespace Quickstart
{
public sealed partial class MainWindow : Window
{
public MainWindow()
{
this.InitializeComponent();
ViewModel = new RecordingViewModel();
}
public RecordingViewModel ViewModel{ get; set; }
}
}
Der letzte Codeteil ist das Binden eines TextBlock
an die ViewModel.DefaultRecording.OneLineSummary
-Eigenschaft.
<Window x:Class="Quickstart.MainWindow" ... >
<Grid>
<TextBlock Text="{x:Bind ViewModel.DefaultRecording.OneLineSummary}"
HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Grid>
</Window>
Hier sehen Sie das Ergebnis.
Binden an eine Sammlung von Elementen
Ein häufiges Szenario ist das Binden an eine Sammlung von Geschäftsobjekten. In C# stellt die generische ObservableCollection<T>-Klasse eine gute Wahl für die Datenbindung bei Sammlungen dar, da sie die Schnittstellen INotifyPropertyChanged und INotifyCollectionChanged implementiert. Diese Schnittstellen stellen Änderungsbenachrichtigungen für Bindungen bereit, wenn Elemente hinzugefügt oder entfernt werden oder eine Eigenschaft der Liste selbst geändert wird. Wenn Ihre gebundenen Steuerelemente bei Änderungen an Eigenschaften von Objekten in der Sammlung aktualisiert werden sollen, muss das Geschäftsobjekt auch INotifyPropertyChanged
implementieren. Weitere Informationen finden Sie unter Datenbindung im Detail.
In diesem nächsten Beispiel wird eine ListView an eine Sammlung von Recording
-Objekten gebunden. Beginnen wir mit dem Hinzufügen der Sammlung zu unserem Ansichtsmodell. Fügen Sie einfach diese neuen Mitglieder zur RecordingViewModel
-Klasse hinzu.
public class RecordingViewModel
{
...
private ObservableCollection<Recording> recordings = new ObservableCollection<Recording>();
public ObservableCollection<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) });
}
}
Binden Sie dann eine ListView an die ViewModel.Recordings
-Eigenschaft.
<Window x:Class="Quickstart.MainWindow" ... >
<Grid>
<ListView ItemsSource="{x:Bind ViewModel.Recordings}"
HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</Window>
Wir haben noch keine Datenvorlage für die Recording
-Klasse bereitgestellt. Daher kann das Benutzeroberflächenframework nur ToString für jedes Element in der ListView aufrufen. Die Standardimplementierung von ToString
besteht darin, den Typnamen zurückzugeben.
Um dies zu beheben, können wir entweder ToString so überschreiben, dass der Wert von OneLineSummary
zurückgegeben wird, oder wir können eine Datenvorlage bereitstellen. Die Datenvorlagenoption ist eine gängigere Lösung und eine flexiblere Lösung. Sie legen eine Datenvorlage mithilfe der ContentTemplate-Eigenschaft eines Inhaltssteuerelements oder mit der ItemTemplate-Eigenschaft eines Elementsteuerelements fest. Im Folgenden finden Sie zwei Möglichkeiten, eine Datenvorlage für Recording
zusammen mit einer Abbildung des Ergebnisses zu entwerfen.
<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>
Weitere Informationen zur XAML-Syntax finden Sie unter Erstellen einer Benutzeroberfläche mit XAML-. Weitere Informationen zum Steuerungslayout finden Sie unter Definieren von Layouts mit XAML.
Hinzufügen einer Detailansicht
Sie können auswählen, dass alle Details von Recording
Objekten in ListView- Elementen angezeigt werden sollen. Aber das beansprucht viel Platz. Stattdessen können Sie nur genügend Daten im Element anzeigen, um es zu identifizieren, und dann können Sie, wenn der Benutzer eine Auswahl trifft, alle Details des ausgewählten Elements in einem separaten Ui-Element anzeigen, das als Detailansicht bezeichnet wird. Diese Anordnung wird auch als Haupt-/Detailansicht oder als Listen-/Detailansicht bezeichnet.
Dazu gibt es zwei Möglichkeiten. Sie können die Detailansicht an die SelectedItem-Eigenschaft der ListView binden. Alternativ können Sie eine CollectionViewSource verwenden. In diesem Fall binden Sie dann sowohl die ListView
als auch die Detailansicht an die CollectionViewSource
(hierdurch wird das derzeit ausgewählte Element für Sie behandelt). Beide Techniken werden unten dargestellt, und beide weisen die gleichen Ergebnisse auf (in der Abbildung dargestellt).
Anmerkung
Bisher haben wir in diesem Thema nur die {x:Bind}-Markuperweiterungverwendet, aber beide Techniken, die unten gezeigt werden, erfordern die flexiblere (aber weniger leistungsfähige) {Binding}-Markuperweiterung.
Sehen wir uns zuerst die SelectedItem-Methode an. Bei einer C#-Anwendung muss lediglich das Markup geändert werden.
<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>
Bei der CollectionViewSource-Technik fügen Sie zuerst eine CollectionViewSource
als Ressource des obersten Grid
hinzu.
<Grid.Resources>
<CollectionViewSource x:Name="RecordingsCollection" Source="{x:Bind ViewModel.Recordings}"/>
</Grid.Resources>
Anmerkung
Die Window-Klasse in WinUI verfügt nicht über eine Resources
-Eigenschaft. Sie können die CollectionViewSource
stattdessen dem obersten Grid
(oder einem anderen übergeordneten UI-Element wie StackPanel
) hinzufügen. Wenn Sie in einer Page
arbeiten, können Sie die CollectionViewSource
den Page.Resources
hinzufügen.
Passen Sie dann die Bindungen in der ListView (die nicht mehr benannt werden muss) und in der Detailansicht so an, dass die CollectionViewSource verwendet wird. Beachten Sie, dass Sie durch die direkte Bindung der Detailansicht an die CollectionViewSource
implizieren, dass Sie in Bindungen, in denen der Pfad in der Sammlung selbst nicht gefunden werden kann, an das aktuelle Element binden möchten. Die CurrentItem
-Eigenschaft muss nicht als Pfad für die Bindung angegeben werden, obwohl dies im Zweifelsfall möglich ist.
...
<ListView ItemsSource="{Binding Source={StaticResource RecordingsCollection}}">
...
<StackPanel DataContext="{Binding Source={StaticResource RecordingsCollection}}" ...>
...
Nachfolgend ist das identische Ergebnis für die beiden Methoden dargestellt.
Formatieren oder Konvertieren von Datenwerten für die Anzeige
Es gibt ein Problem mit dem obigen Rendering. Die ReleaseDateTime
-Eigenschaft ist nicht nur ein Datum, sondern ein Datum und eine Uhrzeit (DateTime). Sie wird also mit höherer Genauigkeit angezeigt, als wir benötigen. Eine Lösung besteht darin, der Recording
Klasse eine Zeichenfolgeneigenschaft hinzuzufügen, die das Äquivalent von ReleaseDateTime.ToString("d")
zurückgibt. Die Benennung dieser Eigenschaft ReleaseDate
gibt an, dass sie ein Datum und keine Datums-und-Uhrzeitangabe zurückgibt. Die Benennung als ReleaseDateAsString
gibt dann auch noch an, dass sie eine Zeichenfolge zurückgibt.
Eine flexiblere Lösung besteht darin, einen Wertkonverter zu verwenden. Hier ein Beispiel, wie Sie einen eigenen Wertkonverter verfassen. Fügen Sie den folgenden Code zu Ihrer Recording.cs Quellcodedatei hinzu.
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();
}
}
Nun können wir eine Instanz von StringFormatter
als Seitenressource hinzufügen und sie in der Bindung des TextBlock
verwenden, in dem die ReleaseDateTime
-Eigenschaft angezeigt wird.
<Grid.Resources>
...
<local:StringFormatter x:Key="StringFormatterValueConverter"/>
</Grid.Resources>
...
<TextBlock Text="{Binding ReleaseDateTime,
Converter={StaticResource StringFormatterValueConverter},
ConverterParameter=Released: \{0:d\}}"/>
...
Wie du oben sehen kannst, verwenden wir für die Flexibilität der Formatierung das Markup, um eine Formatzeichenfolge mithilfe des Konverterparameters in den Konverter zu übergeben. Im in diesem Thema gezeigten Codebeispiel verwendet der C#-Wertkonverter diesen Parameter.
Hier sehen Sie das Ergebnis.
Verwandte Inhalte
Windows developer