XAML Data Binding
Eintrag zuletzt aktualisiert am: 29.03.2013
In
ASP.NET und
Windows Forms unterscheidet man zwischen Datensteuerelementen und sonstigen
Steuerelementen, die keine
Datenbindung unterstützen. In
XAML (
WPF, Silverlight,
WinRT) sind alle visuellen Elemente datenbindungsfähig und in diesen Elementen sind alle
Attribute datenbindungsfähig, die als Abhängigkeitseigenschaften (Dependency Properties) definiert sind. Elemente, die von FrameworkElement abgeleitet sind, unterstützen zusätzlich noch das
Attribut DataContext, dem man beliebige
.NET-
Objekte mit dem Ziel der
Datenbindung übergeben kann.
Datenquellen
Als Datenquellen können in
.NET verwendet werden:
beliebige
Attribute von
WPF-Elementen
in
XAML-Dokumente eingebettete Ressourcen
beliebige
.NET-(Geschäfts-)
Objekte
ADO.NET-
DataSet und -
DataReader
XML-Elemente
Ableitungen von System.Windows.Data.DataSourceProvider. Derzeit gibt es System.Windows.Data.ObjectDataProvider und System.Windows.Data.XmlDataProvider.
WPF unterstützt ein- und zweiseitige
Datenbindung:
OneWay: Bei der einseitigen
Datenbindung von Quelle zu Ziel übergibt ein beliebiges
.NET-
Objekt einem
WPF-Element Daten. Das
WPF-Element aktualisiert aber nicht das
.NET-
Objekt.
OneWayToSource: Bei der einseitigen
Datenbindung von Ziel zu Quelle speichert das
WPF-Element Informationen in einem
.NET-
Objekt, ohne dass es vorher Daten von dort geholt hätte.
TwoWay: Bei der zweiseitigen
Datenbindung holt das
WPF-Element Daten von der Quelle und schreibt Änderungen dorthin zurück. Dies ist der klassische Fall eines Texteingabefelds.
Wenn im Rahmen einer
Datenbindung das Ziel automatisch aktualisierte Werte von der Datenquelle erhalten soll, muss die Datenquelle entweder Abhängigkeitseigenschaften bereitstellen oder aber die Schnittstellen
System.ComponentModel.INotify
PropertyChanged bzw.
System.Collections.Specialized.INotifyCollectionChanged implementieren. Geschäftsobjekte werden in der Regel den letzteren Weg gehen, da die Basisklasse Dependency
Property für
WPF-Abhängigkeitseigenschaften im
WPF-Namensraum System.Windows definiert ist und der Entwickler sonst eine falsche Schichtenbeziehung schaffen würde.
Beispiel
Im Folgenden soll die
Liste der Flüge in der Flugbuchungsmaske gestaltet werden.
Datenbeschaffung
Die Flugbuchungsmaske bezieht ihre Daten von der Geschäftslogik, die mit dem
ADO.NET Entity Frame-work arbeitet.
De.
WWWings.GL.FlugBLManager flugManager = new de.
WWWings.GL.FlugBLManager();
…
private void HoleDatenFuer
ListBox(int PID)
{
if (this.C_Fluege == null) return;
//
Datenbindung für
ListBox
List<Flug> fluege = null;
if ((this.C_Filter.SelectedValue == null) ||
(this.C_Filter.SelectedValue.ToString() == "Alle Flüge"))
fluege = flugManager.GetFluegeMitStatusFuerPassagier(PID, BuchungsFilterStatus.Alle);
if ((this.C_Filter.SelectedValue != null) ||
(this.C_Filter.SelectedValue.ToString() == "Nur gebuchte"))
fluege = flugManager.GetFluegeMitStatusFuerPassagier(PID, BuchungsFilterStatus.NurGebuchte);
if ((this.C_Filter.SelectedValue != null) ||
(this.C_Filter.SelectedValue.ToString() == "Nur nicht gebuchte"))
fluege = flugManager.GetFluegeMitStatusFuerPassagier(PID, BuchungsFilterStatus.NurNichtGebuchte);
this.C_Fluege.DataContext = fluege;
}
Listing 15.14 Datenbelieferung der Listbox in Abhängig von der Auswahl in der ComboBox
Datendarstellung
Dem
ListBox-
Steuerelement ist mitzuteilen, dass es die Elemente aus einem
Datenbindungsvorgang bezie-hen soll und wie die
Datenbindungsrichtung sein soll. OneWay reicht hier aus. Danach wird man aber beim Start der Anwendung feststellen, dass das
Steuerelement zwar so viele Einträge anzeigt, wie es Datensätze gibt, aber dass nur der Name der Klasse angezeigt wird, weil das
Steuerelement nicht weiß, welche Daten es anzeigen soll. Daher ist es notwendig, in einer
Datenbindungsvorlage (Data
Template) zu definieren, welche Informationen wie ausgegeben werden sollen.
Das Data
Template definiert auch die Kontextmenüeinträge.
<Data
Template>
<Border Name="C_Border" BorderBrush="
Blue" BorderThickness="1"
Padding="5" Margin="5">
<Border.Context
Menu>
<Context
Menu>
<
MenuItem Header="Details anzeigen" Click="C
DetailsClick"></
MenuItem>
<
MenuItem Header="Stornieren" Click="C
StornoClick"></
MenuItem>
</Context
Menu>
</Border.Context
Menu>
<Stack
Panel>
<Stack
Panel Orientation="Horizontal">
<
CheckBox></
CheckBox>
<TextBlock Text="Flug "/>
<TextBlock Text="{Binding Path=FlugNr}" />
<TextBlock Text=" am "/>
<TextBlock Text="{Binding Path=Datum}"/>
</Stack
Panel>
<Stack
Panel Orientation="Horizontal">
<TextBlock Text="von "/>
<TextBlock Text="{Binding Path=Abflugort}"/>
<TextBlock Text=" nach "/>
<TextBlock Text="{Binding Path=Zielort}"/>
<Line Stroke="LightSteel
Blue"></Line>
</Stack
Panel>
</Stack
Panel>
</Border>
</Data
Template>
Listing 15.15
Datenbindungsvorlage
Datenabhängige Darstellung
Durch so genannte Daten-Trigger kann der Entwickler festlegen, dass unter bestimmten Voraussetzungen die Formatierung geändert werden soll. Das folgende Fragment, das innerhalb von <Data
Template> zu verwenden ist, definiert einen roten anstelle eines blauen Rahmens für alle Flüge, die bereits ausgebucht sind. Dabei greift der Trigger auf das berechnete
Attribut IstAusgebucht der Klasse Flug zu.
<Data
Template.Triggers>
<DataTrigger Binding="{Binding Path=IstAusgebucht, Mode=OneWay}">
<DataTrigger.Value>true</DataTrigger.Value>
<
Setter TargetName="C_Border"
Property="BorderBrush" Value="Red"/>
</DataTrigger>
</Data
Template.Triggers>
Listing 15.16 Daten-Trigger für eine
Datenbindungsvorlage
Zugriff auf den aktuellen Datensatz
Für die Kontextmenüfunktionen muss man auslesen können, welcher der aktuelle Datensatz ist. Der Weg zur Ermittlung des aktuellen Datensatzes geht nicht über das
ListBox-Element (also das
Datenbindungsziel), sondern über die Datenquelle. Bei der
Datenbindung legt
WPF automatisch eine Sicht auf die Daten an. Diese Sicht (abhängig von der Art der Daten CollectionView, ListCollectionView oder BindingListCollectionView) verwaltet in CurrentItem das aktuelle Element. Man erhält die Sicht von CollectionViewSource.GetDefaultView(), wobei als Parameter ein Verweis auf die verwendete Datenob-jektmenge anzugeben ist. Zur Vermeidung einer Fallunterscheidung verwendet man am besten die gemeinsame Schnittstelle ICollectionView.
Private void C
StornoClick(object sender, RoutedEventArgs e)
{
System.ComponentModel.ICollectionView view = CollectionViewSource.GetDefaultView(bb);
de.
WWWings.PassagierSystem.Buchung b = (de.
WWWings.PassagierSystem.Buchung)view.CurrentItem;
de.
WWWings.Buchung_BLManager.BuchungenLoeschen(b.Buchungscode);
MessageBox.Show("Flug wurde storniert: " + b.Buchungscode.ToString());
}
Listing 15.17 Zugriff auf das aktuelle Datenelement