24.5 Datenbindung an ADO.NET- und LINQ-Datenquellen
In den bisherigen Beispielen wurden immer benutzerdefinierte CLR-Objekte als Datenquelle verwendet, manchmal nur als einzelne Objekte, in anderen Beispielen in Form von Auflistungen. In den meisten Fällen werden aber Daten aus einer Datenbank bezogen und in einem Fenster zur Anzeige gebracht. Mit ADO.NET und dem Entity Framework gibt es unter .NET zwei herausragende Technologien, die den Zugriff auf Datenbanken unterstützen. In diesem Abschnitt wollen wir uns ansehen, wie wir Daten aus diesen beiden Quellen in der WPF nutzen können.
Die Themen ADO.NET und Entity Framework werden erst nach dem Themenkomplex der WPF behandelt. Auch wenn Sie möglicherweise noch keine Kenntnisse in den beiden Technologien haben, sollten wir das Thema der Bindung der WPF-Elemente an diese Datenquellen nicht verschieben. Hier kommt es auch weniger auf die Details an, wie die Daten bereitgestellt werden, sondern vielmehr darauf, wie das Resultat der Datenabfrage in der WPF verarbeitet wird. Sollten Sie aber dennoch wissen wollen, was sich hinter einem bestimmten Typ und einer bestimmten Syntax verbirgt, sollten Sie das entsprechende Kapitel vorab lesen.
Ein weiterer Hinweis sei an dieser Stelle gestattet. In diesem Buch wird, wenn wir die Themenkreise ADO.NET und das Entity Framework erörtern, mit der altbekannten, fast schon als klassisch zu bezeichnenden Datenbank Northwind gearbeitet. In Kapitel 31 ist beschrieben, wie Sie diese Datenbank beziehen und in SQL Server 2008 Express Edition einbinden können.
24.5.1 Das Binden an ADO.NET-Objekte
In den letzten Abschnitten haben wir mit benutzerdefinierten Klassen gearbeitet, die uns als Datenquelle dienten. Im Grunde genommen ändert sich zunächst einmal nichts, wenn Sie die spezifischen ADO.NET-spezifischen Objekte DataSet bzw. DataTable an WPF-Elemente binden wollen.
Im folgenden Listing wird die Tabelle Products der Northwind-Datenbank abgefragt und an den Datenkontext des Window übergeben:
public MainWindow()
{
InitializeComponent();
SqlConnection con = new SqlConnection(@"Data Source=.\SQLEXPRESS;"
+ "DataBase=Northwind;Integrated Security=True");
SqlCommand cmd = new SqlCommand("SELECT * FROM Products", con);
DataSet ds = new DataSet();
SqlDataAdapter da = new SqlDataAdapter(cmd);
da.Fill(ds);
this.DataContext = ds.Tables[0];
}
Listing 24.37 Das Binden einer ADO.NET-Tabelle an einen Datenkontext
Die durch ds.Tables[0] beschriebene Tabelle wird genauso dem DataContext übergeben, als sei es eine ganz normale Collection.
Es gibt allerdings einen Unterschied, den Sie beachten müssen, wenn Sie eine DataTable an die Eigenschaft ItemsSource eines Listensteuerelements binden wollen. Die Eigenschaft ItemsSource verlangt nämlich, dass die anzubindende Datenquelle die Schnittstelle IEnumerable unterstützt. Genau das ist bei einem DataTable-Objekt nicht der Fall. In solchen Fällen bietet sich die Lösung an, auf die DataTable deren Methode DefaultView aufzurufen, wie im nächsten Listing gezeigt wird.
[...]
DataTable tbl = ds.Tables[0];
dataGrid1.ItemsSource = tbl.DefaultView;
Listing 24.38 Binden einer DataTable an die Eigenschaft »ItemsSource«
Hier sei dataGrid1 der Bezeichner eines WPF-DataGrid-Elements.
Die Methode DefaultView liefert ein Objekt vom Typ DataView zurück, das die erforderliche Schnittstelle IEnumerable implementiert. Dabei handelt es sich um eine Sicht (View) auf die Tabelle, mit der die Tabelle auch gefiltert, sortiert und durchsucht werden kann.
24.5.2 Das Binden an LINQ-Ausdrücke
Eine zweite wichtige Datenquelle wird durch LINQ-Ausdrücke beschrieben. LINQ-Ausdrücke werden unter anderem auch vom Entity Framework zur Abfrage von Daten benutzt. LINQ-Ausdrücke liefern als Resultat einer Abfrage ein Ergebnis, das durch das Interface IEnumerable<T> beschrieben wird. Wenige Zeilen vorher haben Sie erfahren, dass zur Bindung einer Datenquelle an die Eigenschaft ItemsSource die Datenquelle die Schnittstelle IEnumerable implementieren muss. ItemsSource und das Ergebnis einer LINQ-Abfrage passen also prima zusammen, da IEnumerable<T> natürlich IEnumerable implementiert. Somit müssen wir nicht im Geringsten in eine Trickkiste greifen, sondern können das Resultat einer LINQ-Abfrage direkt an die ItemsSource-Eigenschaft binden.
Das folgende Listing werden Sie später im Buch noch einmal wiederfinden, wenn ich Ihnen die Grundzüge des Entity Frameworks erläutere. Es wird auch hier die Products-Tabelle der Northwind-Datenbank abgefragt, wobei in die Ergebnismenge nur die Datensätze geschrieben werden, deren Einzelpreis größer oder gleich 50 ist.
NorthwindEntities context = new NorthwindEntities();
var products = from p in context.Products
where p.UnitPrice >= 50
select new { p.ProductID, p.ProductName, p.UnitPrice};
dataGrid1.ItemsSource = products;
Listing 24.39 Anbindung einer LINQ-Datenquelle
Wo Licht ist, ist auch Schatten. So auch in diesem Fall. Im Gegensatz zu ObservableCollection und DataTable wird vom IEnumerable<T>-Interface das Hinzufügen und Löschen von Listenmitgliedern nicht unterstützt. Doch LINQ bietet mit den beiden Methoden ToList und ToArray einfach umzusetzende Lösungen.
Während ToArray ein Array vom Typ T (also ein Array generischer Typen) zurückliefert, ist es bei der Methode ToList der Typ List<T>. Damit liegen in beiden Fällen Auflistungen vor, die sich in ihrer Verhaltensweise nicht von den anderen Auflistungen unterscheiden und – um es wieder auf den Punkt zu bringen – auch das Hinzufügen und Löschen von Listenelementen ermöglichen.
Betrachten wir den LINQ-Ausdruck aus Listing 24.39. Mit dem Aufruf der Methode ToList wandeln wir das IEnumerable<T>-Resultat nun noch in List<T> um:
var products = from p in context.Products
where p.UnitPrice >= 50
select new { p.ProductID, p.ProductName, p.UnitPrice};
List<Product> liste = products.ToList();
Listing 24.40 LINQ-Abfrageresultat in den Typ »List<T>« umwandeln
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.