Galileo Computing < openbook > Galileo Computing - Professionelle Bücher. Auch für Einsteiger.
Professionelle Bücher. Auch für Einsteiger.

Inhaltsverzeichnis
Vorwort zur 6. Auflage
1 Allgemeine Einführung in .NET
2 Grundlagen der Sprache C#
3 Das Klassendesign
4 Vererbung, Polymorphie und Interfaces
5 Delegates und Ereignisse
6 Strukturen und Enumerationen
7 Fehlerbehandlung und Debugging
8 Auflistungsklassen (Collections)
9 Generics – Generische Datentypen
10 Weitere C#-Sprachfeatures
11 LINQ
12 Arbeiten mit Dateien und Streams
13 Binäre Serialisierung
14 XML
15 Multithreading und die Task Parallel Library (TPL)
16 Einige wichtige .NET-Klassen
17 Projektmanagement und Visual Studio 2012
18 Einführung in die WPF und XAML
19 WPF-Layout-Container
20 Fenster in der WPF
21 WPF-Steuerelemente
22 Elementbindungen
23 Konzepte von WPF
24 Datenbindung
25 Weitere Möglichkeiten der Datenbindung
26 Dependency Properties
27 Ereignisse in der WPF
28 WPF-Commands
29 Benutzerdefinierte Controls
30 2D-Grafik
31 ADO.NET – Verbindungsorientierte Objekte
32 ADO.NET – Das Command-Objekt
33 ADO.NET – Der SqlDataAdapter
34 ADO.NET – Daten im lokalen Speicher
35 ADO.NET – Aktualisieren der Datenbank
36 Stark typisierte DataSets
37 Einführung in das ADO.NET Entity Framework
38 Datenabfragen des Entity Data Models (EDM)
39 Entitätsaktualisierung und Zustandsverwaltung
40 Konflikte behandeln
41 Plain Old CLR Objects (POCOs)
Stichwort

Download:
- Beispiele, ca. 62,4 MB

Buch bestellen
Ihre Meinung?

Spacer
Visual C# 2012 von Andreas Kühnel
Das umfassende Handbuch
Buch: Visual C# 2012

Visual C# 2012
Rheinwerk Computing
1402 S., 6., aktualisierte und erweiterte Auflage 2013, geb., mit DVD
49,90 Euro, ISBN 978-3-8362-1997-6
Pfeil 24 Datenbindung
Pfeil 24.1 Bindung benutzerdefinierter Objekte
Pfeil 24.1.1 Ein Objekt mit XAML-Code erzeugen und binden
Pfeil 24.1.2 Ein Objekt mit C#-Code erzeugen und binden
Pfeil 24.1.3 Aktualisieren benutzerdefinierter Objekte
Pfeil 24.2 Auflistungen binden
Pfeil 24.2.1 Allgemeine Gesichtspunkte
Pfeil 24.2.2 Anbindung an eine »ListBox«
Pfeil 24.2.3 Änderungen der Collection an die bindenden Elemente weiterleiten
Pfeil 24.3 Validieren von Bindungen
Pfeil 24.3.1 Die Validierung im Datenobjekt
Pfeil 24.3.2 Eine benutzerdefinierte »ValidationRule«
Pfeil 24.3.3 Validierung mit der Schnittstelle »IDataErrorInfo«
Pfeil 24.3.4 Fehlerhinweise individuell anzeigen
Pfeil 24.3.5 Ereignisauslösung bei einem Validierungsfehler
Pfeil 24.4 Daten konvertieren
Pfeil 24.4.1 Mehrfachbindungen und Konverterklassen
Pfeil 24.5 Datenbindung an ADO.NET- und LINQ-Datenquellen
Pfeil 24.5.1 Das Binden an ADO.NET-Objekte
Pfeil 24.5.2 Das Binden an LINQ-Ausdrücke

Galileo Computing - Zum Seitenanfang

24.2 Auflistungen bindenZur nächsten Überschrift

Die Bindung eines einzelnen Objekts an ein Steuerelement haben Sie nun gesehen. Meistens hat man jedoch nicht mit einzelnen Objekten, sondern mit Listen zu tun, die viele Objekte enthalten. Der recht allgemeine Begriff »Liste« kann durch viele spezielle Mengen ersetzt werden: Es kann sich dabei um ein herkömmliches Array handeln, um eine Collection oder gar um die Tabelle einer Datenbank.

Das Binden einer Liste an ein Steuerelement ist nicht mehr ganz so einfach wie das Binden eines einzelnen Objekts. Auch die Anforderungen, die an die bindungsfähigen Listensteuerelemente gestellt werden, sind komplexer. Wir müssen uns daher zuerst einmal ansehen, wie wir Listen an die entsprechenden Steuerelemente binden können.


Galileo Computing - Zum Seitenanfang

24.2.1 Allgemeine GesichtspunkteZur nächsten ÜberschriftZur vorigen Überschrift

Allzu viele bindungsfähige Steuerelemente hat die WPF nicht zu bieten. Mit ComboBox, ListBox, ListView und DataGrid sind bereits alle wesentlichen genannt. Diese Elemente sind alle von der gemeinsamen Basisklasse ItemsControl abgeleitet, die den Steuerelementen die Fähigkeit verleiht, Listen anzubinden.

Auch wenn Ihnen im ersten Moment die Auswahl spärlich erscheint, sollten Sie berücksichtigen, dass auch das Layout der bindungsfähigen Listenelemente mit Templates an die unterschiedlichsten Anforderungen angepasst werden kann. Natürlich werden wir auch darauf noch zu sprechen kommen.

Wenn wir uns über die Bindung von Listen unterhalten, sind es immer drei Eigenschaften, die eine entscheidende Rolle spielen. Diese sind Tabelle 24.1 zu entnehmen.

An ItemsControl-Steuerelemente lassen sich alle möglichen Auflistungen binden. Es kann sich ebenso um einfache Arrays handeln wie um spezialisierte Auflistungen. Die einzige Bedingung ist die Unterstützung durch das Interface IEnumerable. Es sei bereits an dieser Stelle darauf hingewiesen, dass zum Ändern oder Hinzufügen von Listenelementen noch weitere Gesichtspunkte eine wichtige Rolle spielen.

Tabelle 24.1 Eigenschaften der Klasse »ItemsControl« im Zusammenhang mit der Bindung

Eigenschaft Beschreibung

DisplayMemberPath

Diese Eigenschaft beschreibt einen Pfad zu einem Wert im Objekt. Der Wert wird zur Anzeige verwendet.

ItemsSource

Diese Eigenschaft verweist auf ein Objekt vom Typ IEnumerable. Dabei handelt es sich um das Listenobjekt, das im Steuerelement angezeigt wird.

ItemTemplate

Diese Eigenschaft definiert ein DataTemplate für die im Steuerelement enthaltenen Objekte.


Galileo Computing - Zum Seitenanfang

24.2.2 Anbindung an eine »ListBox«Zur nächsten ÜberschriftZur vorigen Überschrift

Im Beispiel ChangeNotificationSample hatten wir eine Person an die Controls im Fenster gebunden. Im nächsten Beispiel verwenden wir wieder dieselbe Klasse, möchten uns aber eine Liste von Personen in einer ListBox anzeigen lassen. Darüber hinaus sollen die Daten der aktuell in der ListBox selektierten Person in Textboxen angezeigt werden. Das Window zur Laufzeit können Sie in Abbildung 24.2 sehen.

Abbildung

Abbildung 24.2 Ausgabe des Beispiels »ListBoxBindingSample«

Sehen wir uns zuerst den gesamten XAML- und C#-Code des Beispiels an.

// Beispiel: ..\Kapitel 24\ListBoxBindingSample

<Window ...>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<ListBox Name="listBox1"></ListBox>
<Grid DataContext="{Binding ElementName=listBox1, Path=SelectedItem}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Label>Name:</Label>
<Label>Alter:</Label>
<Label>Adresse:</Label>
<TextBox Text="{Binding Path=Name}"></TextBox>
<TextBox Text="{Binding Path=Alter}"></TextBox>
<TextBox Text="{Binding Path=Adresse}"></TextBox>
</Grid>
</Grid>
</Window>

Der C#-Code in der Code-Behind-Datei:

public partial class MainWindow : Window {

public MainWindow() {
InitializeComponent();
listBox1.ItemsSource = GetPersons();
listBox1.DisplayMemberPath = "Name";
listBox1.SelectedIndex = 0;
listBox1.Focus();
}

private List<Person> GetPersons() {
List<Person> liste = new List<Person>();
liste.Add(new Person { Name = "Schulze", Alter = 56,
Adresse = "Bremen" });
[...]
return liste;
}
}

Listing 24.11 Programmcode des Beispiels »ListBoxBindingSample«

Die Bindung der ListBox an die Daten, die in diesem Beispiel durch die Methode GetPersons geliefert werden, erfolgt im Konstruktor mit der Methode ItemsSource. Jedes ListBoxItem-Element beschreibt genau eine Person mit ihren insgesamt drei Eigenschaften. Wir müssen deshalb mit der Eigenschaft DisplayMemberPath die anzuzeigende Eigenschaft spezifizieren, da wir ansonsten nur den voll qualifizierten Klassenbezeichner in der ListBox sehen.

Das aktuell in der ListBox selektierte ListBoxItem und das sich dahinter befindende Person-Objekt wird im zweiten, untergeordneten Grid mit dessen Eigenschaft DataContext gebunden:

<Grid DataContext="{Binding ElementName=listBox1, Path=SelectedItem}">
[...]
</Grid>

Die Textboxen, die sich innerhalb dieses Grid befinden, können sich ihrerseits an die durch den Datenkontext beschriebene Datenquelle (also das selektierte ListBoxItem) binden, müssen aber mit Path die Eigenschaft angeben, die von der Property Text angezeigt werden soll:

<TextBox Text="{Binding Path=Name}"></TextBox>

Wenn Sie dieses Beispiel zur Laufzeit ausprobieren, werden Sie feststellen, dass Änderungen, die Sie in den Textboxen eintragen, sofort im Person-Objekt gespeichert sind. Sie brauchen dazu nur innerhalb der Liste zu einem anderen Eintrag und wieder zurück zum edierten Element zu navigieren, um das bewiesen zu sehen. Dieses Verhalten wird durch den voreingestellten Two-Way-Modus der TextBox sichergestellt.


Galileo Computing - Zum Seitenanfang

24.2.3 Änderungen der Collection an die bindenden Elemente weiterleitenZur nächsten ÜberschriftZur vorigen Überschrift

In Abschnitt 24.1.3 haben Sie gesehen, dass an eine Klasse besondere Anforderungen gestellt werden, damit sie Änderungen an die bindenden Elemente weiterleitet. Zur Erinnerung: Dazu war die Implementierung des Interfaces INotifyPropertyChanged notwendig. Das gilt sehr ähnlich auch für eine Collection. Hier lautet die Forderung, dass die Auflistung neben INotifyPropertyChanged eine weitere Schnittstelle implementieren muss, nämlich INotifyCollectionChanged. Erst mit dieser Schnittstelle ist es möglich, bindende Elemente zu informieren, wenn der Auflistung ein neues Objekt hinzugefügt oder ein Auflistungsmitglied gelöscht worden ist.

Sie brauchen aber nicht selbst eine solche Klasse zu entwickeln, denn mit der generischen Klasse ObservableCollection<> im Namespace System.Collections.ObjectModel stellt Ihnen .NET bereits eine passende zur Verfügung. Diese Collection kann ähnlich benutzt werden wie eine herkömmliche Auflistung. Damit wird es sehr einfach, eine Liste mehrerer Objekte vom Typ Person zu beschreiben:

ObservableCollection<Person> liste = new ObservableCollection<Person>();

Damit steht uns ein Auflistungsobjekt zur Verfügung, das wir zum Füllen von Steuerelementen wie der ComboBox oder der ListBox einsetzen können.

Erweiterung des Beispiels »ListBoxBindingSample«

Es bietet sich an dieser Stelle natürlich an, das Beispiel aus dem letzten Abschnitt (ListBoxBindingSample) zu ändern und es um Fähigkeiten zu ergänzen, Änderungen am Inhalt der Collection den bindenden Elementen automatisch mitzuteilen. Das Layout des Fensters soll so gestaltet werden, wie in Abbildung 24.3 zu sehen ist.

Abbildung

Abbildung 24.3 Fenster des Beispiels »ObservableCollectionSample«

Klickt der Anwender auf die Schaltfläche Hinzufügen, werden die drei Textboxen geleert, und der Anwender kann die Daten der neuen Person eintragen. Gleichzeitig werden auch die beiden Schaltflächen Speichern und Abbrechen aktiviert, die nach dem Starten der Anwendung zunächst deaktiviert sind. Das Löschen aus der Liste bezieht sich immer auf die in dem Moment in der ListBox ausgewählte Person.

Als Erstes muss die Methode GetPersons statt eines Objekts vom Typ List<Person> ein Objekt vom Typ ObservableCollection<Person> zurückliefern:

private ObservableCollection<Person> GetPersons()
{
liste.Add(new Person { Name = "Schulze", Alter = 56,
Adresse = "Bremen" });
[...]
return liste;
}

Listing 24.12 Die Anpassung der Methode »GetPersons«

Die Instanziierung des Collection-Objekts erfolgt sinnvollerweise auf Klassenebene, damit auch andere Methoden Zugriff auf das Objekt haben.

Nach der Ergänzung des Window um die entsprechenden Schaltflächen offenbaren sich bei der Entwicklung schnell zwei Probleme:

  • Wir müssen den Inhalt der TextBox, die das Alter der Person als Zeichenfolge angibt, in einen null-fähigen Integer konvertieren.
  • Nicht minder schwer ist ein anderes Problem, das im Zusammenhang mit der Datenbindung der Textboxen auftaucht. Im Grunde genommen soll ja erst in dem Moment die Collection und auch die Anzeige in der ListBox aktualisiert werden, wenn auf die Schaltfläche Speichern geklickt wird. Bedingt durch die Datenbindung wird aber schon beim Verlassen jeder TextBox die ListBox aktualisiert – also zu einem zu frühen Zeitpunkt.

Lassen Sie uns zunächst das erstgenannte Problem lösen. Dieses tritt auf, wenn auf die Schaltfläche Hinzufügen geklickt wird und die Inhalte der Textboxen dazu verwendet werden, das neue Person-Objekt mit den entsprechenden Eigenschaftswerten zu erzeugen. Das Alter kann per Definition in der Klasse null sein. Also muss der Inhalt der TextBox, also eine Zeichenfolge, in den Typ int? konvertiert werden. Da die üblichen Wege der Typkonvertierung versagen, muss ein anderer Weg beschritten werden.

Eine relativ einfache Lösung bietet sich über die statische Methode ChangeType der Klasse Convert an, die wie folgt definiert ist:

public static Object ChangeType(Object, Type)

Dem ersten Parameter wird ein Objekt übergeben, das die Schnittstelle IConvertible implementiert. Ein Blick in die Dokumentation verrät uns, dass String dieses Interface unterstützt. Der zweite Parameter gibt den Typ des zurückzugebenden Objekts an. Da der Rückgabewert der Methode ChangeType vom Typ Object ist, muss am Ende nur noch eine entsprechende Typkonvertierung durchgeführt werden.

Es bietet sich an, für die endgültige Konvertierung eines String in int? eine Methode zu definieren, die als Erweiterungsmethode der Klasse String bereitgestellt wird:

static class ExtensionMethods {
public static T To<T>(this string text) {
return (T)Convert.ChangeType(text, typeof(T));
}
}

Listing 24.13 Erweiterungsmethode zur Typkonvertierung

Damit ist das erste der beiden Probleme gelöst. Kommen wir nun zum zweiten.

Eine einmal eingestellte Datenbindung ist immer aktiv. Nehmen wir an, der Anwender möchte eine neue Person hinzufügen. Er klickt also die entsprechende Hinzufügen-Schaltfläche an und trägt als Erstes den Namen der neuen Person ein. Wird die TextBox verlassen, wird der Wert sofort in die ListBox eingetragen, ohne dass das neue Objekt tatsächlich schon angelegt ist. Das ist der Preis der Datenbindung – in diesem Moment allerdings ein Preis, der nicht vorteilhaft ist.

Die Lösung dieses Problems ist recht einfach. Wir müssen die Bindung mit C#-Programmcode aufheben, wenn der Anwender die Schaltfläche Hinzufügen anklickt. Die Bindung muss allerdings aktiviert werden, wenn der Anwender auf eine der beiden Schaltflächen Abbrechen oder Speichern geklickt hat.

// Beispiel: ..\Kapitel 24\ObservableCollectionSample

private void btnAdd_Click(object sender, RoutedEventArgs e) {
txtName.Text = ""; txtAddress.Text = ""; txtAge.Text = "";
txtName.Focus();

// Bindung lösen

BindingOperations.ClearBinding(txtName, TextBox.TextProperty);
BindingOperations.ClearBinding(txtAddress, TextBox.TextProperty);
BindingOperations.ClearBinding(txtAge, TextBox.TextProperty);
[...]
}

private void btnSave_Click(object sender, RoutedEventArgs e) {
Person person = new Person { Name = txtName.Text,
Adresse = txtAddress.Text };
if (txtAge.Text == "") person.Alter = null;
else person.Alter = (txtAge.Text).To<int>();
liste.Add(person);

// Bindung erstellen

SetBinding();
[...]
}

private void btnCancel_Click(object sender, RoutedEventArgs e) {

// Bindung erstellen

SetBinding();
listBox1.SelectedIndex = 0;
[...]
}

private void SetBinding() {

// Bindungen neu festlegen

Binding binding = new Binding("Name");
txtName.SetBinding(TextBox.TextProperty, binding);
binding = new Binding("Adresse");
txtAddress.SetBinding(TextBox.TextProperty, binding);
binding = new Binding("Alter");
txtAge.SetBinding(TextBox.TextProperty, binding);
}

private void btnDelete_Click(object sender, RoutedEventArgs e) {
int index = listBox1.SelectedIndex;
liste.RemoveAt(index);
if (liste.Count == 0) btnDelete.IsEnabled = false;
else listBox1.SelectedIndex = 0;
}

Listing 24.14 C#-Code aus dem Beispiel »ObservableCollectionSample«



Ihr Kommentar

Wie hat Ihnen das <openbook> gefallen? Wir freuen uns immer über Ihre freundlichen und kritischen Rückmeldungen.

>> Zum Feedback-Formular
<< zurück
  Zum Katalog
Zum Katalog: Visual C# 2012

Visual C# 2012
Jetzt bestellen


 Ihre Meinung?
Wie hat Ihnen das <openbook> gefallen?
Ihre Meinung

 Buchempfehlungen
Zum Katalog: Professionell entwickeln mit Visual C# 2012






 Professionell
 entwickeln mit
 Visual C# 2012


Zum Katalog: Windows Presentation Foundation






 Windows Presentation
 Foundation


Zum Katalog: Schrödinger programmiert C++






 Schrödinger
 programmiert C++


Zum Katalog: C++ Handbuch






 C++ Handbuch


Zum Katalog: C/C++






 C/C++


 Shopping
Versandkostenfrei bestellen in Deutschland und Österreich
InfoInfo





Copyright © Rheinwerk Verlag GmbH 2013
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das <openbook> denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


[Rheinwerk Computing]

Rheinwerk Verlag GmbH, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, service@rheinwerk-verlag.de