22.2 Die Klasse »Binding«
Ein Binding-Objekt beschreibt die Bindung zwischen einer Datenquelle und der bindenden Komponente. Meistens wird die Bindung im XAML-Code beschrieben, aber selbstverständlich kann die Bindung wie in Listing 22.3 gezeigt auch im C#-Code erfolgen.
Die wichtigsten Eigenschaften des Binding-Objekts können Sie der folgenden Tabelle entnehmen. Viele der aufgeführten Eigenschaften werden Sie im Verlauf des Kapitels noch innerhalb der Beispielprogramme wiederfinden.
Eigenschaft | Beschreibung |
Diese Eigenschaft gibt an, welches Objekt als Konverter zwischen zwei Datentypen dienen soll. |
|
ElementName |
Diese Eigenschaft gibt den Bezeichner des Steuerelements an, das als Datenquelle dient. |
Diese Eigenschaft definiert einen Standardwert, der verwendet wird, wenn das Binding-Objekt noch keinen Wert zurückliefert. |
|
Wird diese Eigenschaft auf true gesetzt (Standard ist false), werden die Daten aus der Datenquelle asynchron geladen oder asynchron in die Datenquelle geschrieben. |
|
Legt den Bindungsmodus fest. Damit lässt sich die Verhaltensweise einer eventuellen gegenseitigen Aktualisierung zwischen Datenquelle und Datenziel steuern. |
|
Mit diesen Eigenschaften werden Ereignisse ermöglicht, die beim Aktualisieren der Datenquelle oder des Datenziels auftreten. |
|
Path |
Mit Path wird die Eigenschaft festgelegt, an die Daten gebunden werden sollen. |
Diese Eigenschaft legt die Datenquelle fest, allerdings relativ zum Datenziel. |
|
Die Eigenschaft Source legt das Objekt fest, das die Quelle der Datenbindung sein soll. |
|
Mit dieser Eigenschaft wird angegeben, wann die Datenquelle aktualisiert werden soll. |
Der Eigenschaft Path können auf unterschiedlichste Weise Pfade angegeben werden. Im einfachsten Fall geben Sie nur die Eigenschaft an, z. B.:
Path=Text
Es kann sich natürlich um eine untergeordnete Eigenschaft handeln, wie das Beispielprogramm SimpleBinding gezeigt hat:
Path=SelectedItem.Content
Sie könnten auch ohne Probleme an einen bestimmten Listeneintrag der ListBox binden:
Path=Items[0].Content
Nicht unerwähnt bleiben sollte auch, dass mehrere verschachtelte Eigenschaften möglich sind.
Sie können auf die explizite Angabe von Path auch verzichten und direkt die Eigenschaft nennen. Allerdings muss das sofort nach der Angabe des Binding-Objekts in der Markup Extension erfolgen:
Text="{Binding Text, ElementName= ...}"
22.2.1 Die Bindungsrichtung festlegen
Das letzte Beispielprogramm wollen wir für einen weiteren Test benutzen. Wählen Sie dazu zur Laufzeit einen der in der ListBox eingetragenen Namen aus. Dieser wird wegen der definierten Bindung in der TextBox angezeigt. Ändern Sie nun den Namen in der TextBox, und fokussieren Sie durch Drücken der -Taste erneut die ListBox. Sie werden feststellen, dass der neue Name in der TextBox den ursprünglichen im Listenfeld ersetzt. Anscheinend ist sogar das Datenziel in der Lage, die Datenquelle zu aktualisieren. Wir ergänzen nun den Bindungscode der TextBox wie folgt um die Eigenschaft Mode=OneWay:
Text="{Binding ElementName=listBox1, Path=SelectedItem.Content, Mode=OneWay}"
Listing 22.4 Änderung der Datenbindung im Beispielprogramm »SimpleBinding«
Wenn Sie denselben Test nun erneut durchführen, werden Sie einen gravierenden Unterschied feststellen: Der Eintrag in der ListBox wird jetzt nicht mehr verändert.
Durch Angabe des Bindungsmodus mit der Eigenschaft Mode des Binding-Objekts lassen sich offensichtlich die wechselseitigen Änderungen zwischen der Datenquelle und dem Datenziel steuern. Mode kann alle Werte annehmen, die in der Enumeration BindingMode beschrieben werden. Diese können Sie Tabelle 22.2 entnehmen.
Bindungstyp | Beschreibung |
Default |
Hiermit wird der Standardmodus beschrieben, der für die Eigenschaft vordefiniert ist. Dabei handelt es sich meistens um den Modus TwoWay. |
OneTime |
Der Wert wird nur einmal von der Quelle zum Ziel übertragen. Danach findet keine Aktualisierung mehr statt. |
OneWay |
Der Wert wird nur von der Quelle zum Ziel übertragen. |
OneWayToSource |
Der Wert wird von der Quelle zum Ziel übertragen. Ändert sich der Wert im Datenziel, wird die Datenquelle ebenfalls aktualisiert. |
TwoWay |
Die Werte sowohl von der Quelle als auch vom Ziel werden in beide Richtungen übertragen. |
Am besten lassen sich die Einstellungen verstehen, wenn die entsprechenden Effekte in einem Beispiel geprüft werden können. Dazu dient das folgende Beispielprogramm BindungsModi, dessen Darstellung zur Laufzeit Abbildung 22.2 zeigt.
// Beispiel: ..\Kapitel 22\BindungsModi
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="120" /><ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="25"/><RowDefinition />
<RowDefinition /><RowDefinition />
<RowDefinition /><RowDefinition />
</Grid.RowDefinitions>
<Label Content="Bindungsart" />
<Label Content="Quelle" />
<Label Content="Ziel" />
<Label Content="Default" />
<TextBox Name="txtDefaultQuelle" Grid.Column="1" Grid.Row="1" />
<TextBox Name="txtDefaultZiel" Grid.Column="2" Grid.Row="1"
Text="{Binding ElementName=txtDefaultQuelle, Path=Text, Mode=Default}"/>
<Label Content="OneWay" />
<TextBox Name="txtOneWayQuelle" Grid.Column="1" Grid.Row="2"/>
<TextBox Name="txtOneWayZiel" Grid.Column="2" Grid.Row="2"
Text="{Binding ElementName=txtOneWayQuelle, Path=Text, Mode=OneWay}"/>
<Label Content="TwoWay" />
<TextBox Name="txtTwoWayQuelle" Grid.Column="1" Grid.Row="3" />
<TextBox Name="txtTwoWayZiel" Grid.Column="2" Grid.Row="3"
Text="{Binding ElementName=txtTwoWayQuelle, Path=Text, Mode=TwoWay}"/>
<Label Content="OneTime" />
<TextBox Name="txtOneTimeQuelle" Grid.Column="1" Grid.Row="4" />
<TextBox Name="txtOneTimeZiel" Grid.Column="2" Grid.Row="4"
Text="{Binding ElementName=txtTwoWayQuelle, Path=Text,
Mode=OneTime}" Focusable="False" />
<Label Content="OneWayToSource" />
<TextBox Name="txtOneWayToSourceQuelle" Grid.Column="1" Grid.Row="5" />
<TextBox Name="txtOneWayToSourceZiel" Grid.Column="2" Grid.Row="5"
Text="{Binding ElementName=txtOneWayToSourceQuelle, Path=Text,
Mode=OneWayToSource}" />
</Grid>
Listing 22.5 Der XAML-Code des Beispielprogramms (gekürzt)
Abbildung 22.2 Ausgabe des Beispielprogramms »BindungsModi«
In der mittleren Spalte des Grid-Steuerelements sind die Eingabesteuerelemente zu finden, die als Datenquelle dienen, in der rechten Spalte sind die Zielobjekte angeordnet. Sie können in die TextBoxen beider Spalten Änderungen eintragen und dabei beobachten, wie sich der entsprechende Gegenpart der Datenbindung verhält. Beachten Sie, dass Sie in Abhängigkeit vom Modus erst die TextBox verlassen müssen, in der Sie eine Änderung vorgenommen haben, damit die Änderung auf der anderen Seite der Bindung umgesetzt wird.
Auffällig bei den verschiedenen Modi in Tabelle 22.2 sind OneWay und OneWayToSource, die im Grunde genommen beide eine Bindung in der Art einer Einbahnstraße festschreiben. Der Unterschied ist, dass Sie OneWayToSource auch auf der Seite des Datenziels angeben können und es auf diese Weise schaffen, die angebundene Eigenschaft einer Datenquelle auch dann zu aktualisieren, wenn sie nicht als Abhängigkeitseigenschaft implementiert ist, sondern nur als einfache CLR-Eigenschaft.
Der Modus OneWay bietet sich an, wenn dem Benutzer schreibgeschützte Daten angezeigt werden sollen. Die TwoWay-Bindung ist empfehlenswert, wenn der Benutzer in der Lage sein soll, die Daten im Steuerelement zu ändern, und wenn diese Änderung in die Datenquelle zurückgeschrieben werden soll.
22.2.2 Aktualisierung der Bindung
Sehen wir uns noch einmal das Beispielprogramm SimpleBinding an, und hier besonders die Modi TwoWay und OneWay. Ändert sich die Quelle, wird das Ziel der Bindung sofort aktualisiert. Ändert sich hingegen das Datenziel, wird die Quelle erst dann geändert, wenn das Zielelement den Fokus verliert. Das ist nicht immer wünschenswert und kann mit der Eigenschaft UpdateSourceTrigger des Binding-Objekts gesteuert werden. Darüber lässt sich festlegen, dass bei einer Änderung des Zielelements die Quelle erst durch den Aufruf einer Methode aktualisiert wird.
Die möglichen Einstellungen der Eigenschaft UpdateSourceTrigger sind in der gleichnamigen Enumeration UpdateSourceTrigger festgelegt.
Wert | Beschreibung |
Default |
Die Standardeinstellung variiert in Abhängigkeit vom verwendeten Element. Bei einer TextBox ist zum Beispiel die Standardeinstellung LostFocus. In den meisten Fällen handelt es sich aber um PropertyChanged. |
Explicit |
Die Änderung muss explizit durch Aufruf der UpdateSource-Methode des BindingExpression-Objekts erfolgen. |
LostFocus |
Die Quelle wird aktualisiert, wenn die Zielkomponente den Fokus verliert. |
PropertyChanged |
Die Aktualisierung erfolgt bei jeder Änderung. Allerdings beansprucht diese Einstellung die Ressourcen sehr intensiv. |
Denken Sie immer daran, dass die in Tabelle 22.3 angegebenen Werte keinen Einfluss darauf haben, wie das Datenziel aktualisiert wird. Mit UpdateSourceTrigger legen Sie ausschließlich fest, wie die Quelle aktualisiert wird.
Mit diesem Wissen ausgestattet können Sie nun eine Datenbindung auf der Seite des Datenziels definieren, die bei jeder Änderung die Quelle über die Änderung informiert.
<TextBox Text="{Binding ElementName=textBox1, Path=Text, Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}"/>
Listing 22.6 Änderung der Bindungsdaten bei jeder Änderung
Sie sollten insbesondere bei dem Element TextBox berücksichtigen, dass jede Änderung mit der einhergehenden Aktualisierung zu Lasten der Performance geht. Das ist auch der Grund für die Vorgabeeinstellung LostFocus.
Beispiel der Einstellung »UpdateSourceTrigger.Explicit«
Betrachten wir an dieser Stelle die Einstellung Explicit der Eigenschaft UpdateSourceTrigger, da sie sich von den anderen Modi unterscheidet. Dabei wird die Aktualisierung der Quelle durch Aufruf der Methode UpdateSource der Klasse BindingExpression von außen angestoßen. Das könnte beispielsweise durch das Drücken der -Taste der Fall sein oder auch innerhalb eines Ereignishandlers programmiert sein, wie das folgende Beispiel zeigt (siehe auch Abbildung 22.3).
Abbildung 22.3 Fenster des Beispiels »ExplicitUpdate«
// Beispiel: ..\Kapitel 22\ExplicitUpdate
<Window ... >
<StackPanel>
<TextBox Name="txtSource" Margin="10"></TextBox>
<TextBox Name="txtTarget" Margin="10"
Text="{Binding ElementName=txtSource, Path=Text,
UpdateSourceTrigger=Explicit}"/>
<Button Name="btnUpdate" Margin="10" Width="120"
Click="btnUpdate_Click">Aktualisieren</Button>
</StackPanel>
</Window>
Dazu gehört der Ereignishandler der Schaltfläche in der Code-Behind-Datei:
private void btnUpdate_Click(object sender, RoutedEventArgs e) {
BindingExpression binding = txtTarget.GetBindingExpression(TextBox.TextProperty);
binding.UpdateSource();
}
Listing 22.7 C#-Code des Beispiels »ExplicitUpdate«
Hier betritt mit BindingExpression eine weitere Klasse die Bühne. Während ein Objekt vom Typ Binding lediglich die Eigenschaften einer Bindung beschreibt und sich somit auch für mehrere Bindungen eignet, repräsentiert das BindingExpression-Objekt die eigentliche Datenbindung zwischen der Quelle und dem Ziel. Das BindingExpression-Objekt erhalten Sie übrigens auch als Rückgabewert der Methode SetBinding (siehe Listing 22.3).
Neben der im Beispielprogramm eingesetzten Methode UpdateSource besitzt das BindingExpression-Objekt auch eine Methode UpdateTarget, mit der die Eigenschaft im Datenziel aktualisiert werden kann. Diese Methode lässt sich sinnvoll einsetzen, wenn die Datenquelle nur eine gewöhnliche CLR-Eigenschaft ist und nicht das Interface INotifyPropertyChanged implementiert (mehr dazu weiter unten).
22.2.3 Die Ereignisse »SourceUpdated« und »TargetUpdated«
Ändert sich das Datenziel oder die Datenquelle, werden, je nach Situation, die Ereignisse SourceUpdated und TargetUpdated ausgelöst. Das ermöglicht uns, im Kontext einer Aktualisierung weitere Operationen auszuführen. Für Irritationen sorgt am Anfang meistens die Namensgebung. SourceUpdated wird nämlich ausgelöst, wenn sich die Datenquelle aufgrund einer Änderung des Datenziels geändert hat. Analog wird das Ereignis TargetUpdated ausgelöst, wenn sich das Datenziel wegen einer Änderung der Datenquelle anpasst.
Ereignis | Beschreibung |
SourceUpdated |
Dieses Ereignis wird ausgelöst, wenn sich die Datenquelle wegen einer Änderung des Datenziels aktualisiert. |
TargetUpdated |
Dieses Ereignis wird ausgelöst, wenn sich das Datenziel wegen einer Änderung der Datenquelle aktualisiert. |
Die beiden Ereignisse werden nicht standardmäßig ausgelöst, sie müssen vorher aktiviert werden. Dazu dienen die beiden Eigenschaften NotifyOnSourceUpdated und NotifyOnTargetUpdated, die beide auf true festgelegt werden müssen. Darüber hinaus sind natürlich bei Bedarf die Ereignishandler der beiden Ereignisse zu registrieren, die als Attached Events in der Klasse Binding definiert sind.
Sehen wir uns das im folgenden Beispiel an. Dabei wird auf das Fenster aus dem Beispiel ExplicitUpdate des vorhergehenden Abschnitts zurückgegriffen, und es wird um das Ereignis SourceUpdated ergänzt.
<Window ...>
[...]
<TextBox Grid.Column="1" Name="txtSource" Margin="10"></TextBox>
<TextBox Grid.Column="1" Grid.Row="1" Name="txtTarget" Margin="10"
Binding.SourceUpdated="txtTarget_SourceUpdated"
Text="{Binding ElementName=txtSource, Path=Text,
UpdateSourceTrigger=Explicit,
NotifyOnSourceUpdated=True}"/>
<Button Name="btnUpdate" Grid.Column="1" Grid.Row="2" Margin="10"
Click="btnUpdate_Click">Aktualisieren</Button>
[...]
</Window>
Hier noch der C#-Code des Ereignishandlers:
private void txtTarget_SourceUpdated(object sender,
DataTransferEventArgs e) {
MessageBox.Show("Aktualisierung durchgeführt.");
}
Listing 22.8 Ergänzungen im Beispielprogramm »ExplicitUpdate«
Ändern Sie Daten in der als Datenziel definierten unteren TextBox, wird die obere TextBox, die eigentliche Datenquelle erst in dem Moment aktualisiert, wenn auf die Schaltfläche geklickt wird. Gleichzeitig wird das Ereignis SourceUpdated ausgelöst und signalisiert mit einem Nachrichtenfenster die durchgeführte Aktualisierung.
22.2.4 Beenden einer Bindung
Um eine Bindung zu lösen, wird die statische Methode ClearBinding der Klasse BindingOperations aufgerufen und dabei das Zielobjekt und die abhängige Eigenschaft angegeben:
BindingOperations.ClearBinding(textBox1, TextBox.TextProperty);
Hier wird beispielsweise die Eigenschaft Text eines Elements mit dem Namen textBox1 gelöst. Sind mehrere Eigenschaften der Zielkomponente datengebunden, können Sie auch mit einem einzigen Methodenaufruf alle Bindungen mit einer Anweisung lösen. Dazu dient die Methode ClearAllBindings:
BindingOperations.ClearAllBindings(textBox1);
Ihre Meinung
Wie hat Ihnen das Openbook gefallen? Wir freuen uns immer über Ihre Rückmeldung. Schreiben Sie uns gerne Ihr Feedback als E-Mail an kommunikation@rheinwerk-verlag.de.