Das WPF DataGrid zur Darstellung tabellarischer Daten
Inhaltsverzeichnis
Eine moderne tabellarische Darstellung mit dem WPF DataGrid
Herzlich willkommen im heutigen „WPF DataGrid„-Beitrag und schön, dass Du her gefunden hast.
Vermutlich wirst Du aus dem gleichen „Problem“ wie ich damals auf diesen Post gestoßen sein.
Eventuell kennst Du das „WPF DataGrid„-Steuerelement schon, oder möchtest einfach nur Dein Wissen vertiefen.
Vielleicht möchtest Du aber auch einfach nur eine Alternative zum (sorry Winforms) hässlichen DataGridView finden.
Mal ernsthaft: Wer möchte in modernen Anwendungen noch diese an alte Windows Zeiten erinnernde Tabelle verwenden.
Eine teils hängende Performance und eine eher graue Darstellung waren an der Tagesordnung.
Wie Du später in diesem Beispiel noch sehen wirst, bietet das „WPF DataGrid“ tolle Möglichkeiten.
Neben den typischen Reihen, Spalten und sich daraus ergebenden Zellen, gibt es noch mehr zu finden.
Lass‘ uns allerdings vorerst nochmal einen kleinen Schritt zu den Windows Forms (Winforms) zurück machen.
Ich denke, so werden die Unterschiede noch einmal klarer, bzw. der Kontrast ist dadurch stärker.
Ein Rückblick auf die guten alten Winforms
Wie erwähnt gehen wir nochmal einen kleinen Schritt zurück, um zu schauen „wie es mal war„.
Zu dem Zeitpunkt war noch nicht alles so „bunt„, teils „yay“, teils „nay“, oder!?
Okay, abgesehen von der Farbenpracht der Anwendungen gab es natürlich noch viele andere Aspekte.
Zum (für mich, unter Anderem) wichtigsten Aspekt kommen wir nun im nächsten Schritt.
Ein (tatsächlich) bunter Misch-Masch
Wenn ich ehrlich bin, kommen mir gewisse Dinge bei den alten Windows Forms sofort in den Sinn.
Nachträglich betrachtet empfinde ich Diese als ziemlich „komisch“, bzw. eher „unnatürlich„.
Damals hat man z. B. bei DataGridViews Sachen wie Diese hier gemacht:
DataGridView1.Rows.Add(<whatever..>)
Man hat also gängiger weise an den Steuerelementen selbst herumgedoktert.
So gesehen waren die Daten also immer ein Bestandteil des Steuerelements selbst.
Was wir jedoch – schon rein logisch gesehen – erreichen wollen, ist doch eine Darstellung der Daten, oder!?
Sprich die Daten sollen durch etwas dargestellt werden und nicht dieses „Etwas“ selbst sein.
Schauen wir uns im nächsten Schritt an, wie es (unter Anderem) sonst noch laufen kann.
Eine andere Herangehensweise – viele Schritte nach vorn
Viele (ich würde fast sagen – die meisten) NET Entwickler greifen heutzutage auf WPF zurück.
Im Gegensatz zur alten Methodik verwendet WPF eine neue Herangehensweise.
Dabei handelt es sich primär um die saubere Trennung zwischen Oberfläche und Daten.
Es sei an dieser Stelle gesagt, dass es auch bei WPF die Misch-Möglichkeit in gewisser weise gibt.
Ich selbst habe damit allerdings nie großartige Erfahrungen gemacht – auf Grund der neuen Möglichkeiten natürlich bewusst.
Durch die saubere Unterscheidung werden Templates (neben anderen Vorteilen) leichter austauschbar.
Auch wenn diese neue Herangehensweise nur einer der positiven Aspekte ist, ist es denke ich einer der Wichtigsten.
Wie wir gleich noch sehen werden, kommen mit dieser neuen Strukturierung auch weitere Werkzeuge ins Spiel.
Ich spreche da speziell von dem modernen Anwendungs-Entwurfsmuster namens „MVVM“.
Aber genug davon, zurück zur Hauptaussage: Die „bessere“ Herangehensweise bezüglich Daten- & GUI-Trennung.
Softwareentwickler und Designer können sich so trotz separierter Arbeit einander zuarbeiten.
Natürlich basiert dies alles auf einem sauberen vorher abgeklärten Konsens!
3x-mini MVVM-Exkurs
Das „Model-View-ViewModel„-Entwurfsmuster würde mit Sicherheit mehr Aufmerksamkeit verdienen, aber gut..
Ich versuche natürlich, es hier nicht all zu weit auszuführen, daher hier ein paar kurze Argumente/Aspekte.
Das MVVM-Entwurfsmuster spielt in den meisten „Windows Presentation Foundation“ (WPF) Apps eine große Rolle.
Nicht zuletzt deshalb, weil dieses Entwurfsmuster folgende Eigenschaften mit sich bringt:
- Trennung von GUI & Daten
- Moderne Anwendungen
- Intuitive Oberflächen
- Flexible Programmierung
- eine ausgereifte Designer-Unterstützung
- und viel mehr..
Schaue für mehr Informationen gerne im obigen Beitrag vorbei, wundere Dich allerdings nicht.
Bisher habe ich noch keinen separaten Beitrag für MVVM in Visual Basic NET geschrieben.
Das macht allerdings insofern nichts, da die Umsetzung nicht wirklich an der Sprache liegt.
Doch zurück zum Thema: Was machen die restlichen, noch verbliebenen Softwareentwickler?
Die meisten werden wohl die für Windows Forms typischen Steuerelemente verwenden.
Ausnahmen (sorry Leute) verwenden wohl irgendwelche gekauften Steuerelemente und dazugehörige Bibliotheken.
Ich selbst habe zum Beispiel noch nie Geld für Steuerelemente oder ähnliches ausgegeben.
Es gibt meiner Ansicht nach einfach zu viele wirklich gute kostenlose Werkzeuge.
Einige davon wären:
- Autofac
- Caliburn.Micro
- Mahapps Metro
Zu einigen dieser Werkzeuge habe ich schon Beiträge erstellt, Andere folgen in Zukunft!
Das WPF DataGrid selbst
Nach dem ganzen leider für die Suchmaschinenoptimierung notwendigen „Blabla„, nun zum eigentlichen Thema.
Zuerst setzen wir dafür natürlich ein neues Visual Studio Projekt namens „WPF-Anwendung“ auf.
Wenn Du nach einem Thema wie das WPF DataGrid suchst, wird Dir vermutlich bekannt sein wie das geht.
Neues Projekt anlegen
Falls nicht öffnest Du einfach Visual Studio und klickst dort unten rechts auf „neues Projekt erstellen„.
Danach musst Du das passende Projekt-Template auswählen, suche dazu oben rechts einfach nach „wpf“.
Anschließend solltest Du einen Eintrag a la „WPF-Anwendung“ finden.
Achte jedoch darauf, die korrekte Sprache (VB.NET / C#) zu wählen, damit es gleich keine Verwirrung gibt.
Danach bestimmst Du noch den passenden Namen für Projekt und Projektname.
Zum Schluss wählst Du noch das passende NET-Framework aus und – neues Projekt – check!
Ich kann Dir übrigens eine eventuelle Sorge bezüglich der Programmiersprache nehmen.
Die Sprache macht hier für unsere Beispiel keinen wirklich großen oder relevanten Unterschied.
Eine Klasse anlegen – der Bauplan für unsere Daten
Im nächsten Schritt erstellen wir eine kleine Klasse, die dann unsere Daten widerspiegelt.
Zu diesem Zeitpunkt besteht unsere neu erstellte Anwendung praktisch nur aus einem Fenster.
Dabei handelt es sich um die typische WPF-Fenster Klasse, Welche man in so gut wie jedem Programm antrifft.
Lass‘ uns nun einmal unsere Gedanken vom Steuerelement-Kram an sich beiseite schieben.
Werfen wir daher einen Blick auf die „Daten“, bzw. den Bauplan dafür an sich.
Wie sollen wir schließlich auch „etwas“ erstellen, bzw. in einem WPF DataGrid auflisten, wenn es dieses „etwas“ noch nicht gibt.
Erstelle also eine neue Klasse namens „Film“, Diese kannst Du auch ruhig im Wurzelverzeichnis ablegen.
Bedenke, dass ich die Klasse hier erstmal relativ einfach halten werde, also „flach“ und mit wenig Eigenschaften.
Daher werde ich die „Genre„-Eigenschaft z. B. nicht als getrennte Klasse designen, sondern eher als simplen String.
Public Class Film Public Property Titel As String Public Property Genre As String Public Property Bewertung As Decimal End Class
public class Film { public string Titel { get; set; } public string Genre{ get; set; } public decimal Titel { get; set; } }
Daten kreieren – die Film-Instanzen, der Datenkontext und die Auflistung
Nachdem wir nun unseren Bauplan, also die „Film“-Klasse vorbereitet haben, wagen wir uns an die Datenbindung.
Gehe zuerst in die „MainWindow.xaml“-Datei und füge das WPF DataGrid in den standardmäßig leeren Fenster-Code ein.
Die genaue Position für den DataGrid-Code wäre natürlich zwischen den „Grid„-Tags.
<Window x:Class="MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:WpfDataGridExampleVB" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800"> <Grid> <DataGrid /> </Grid> </Window>
Von nun an kommt es darauf an, wie Du vor hast Deine Daten erscheinen zu lassen.
Öffne nun die Code-Datei hinter dem WPF-Fenster, damit wir am Code arbeiten können.
Dazu kannst Du entweder bei geöffnetem Designer „F7“ drücken, oder über den Projektmappen-Explorer gehen.
Klappe dazu den Pfeil des „MainWindows“ im Projektmappen-Explorer auf und doppelklicke die „MainWindow.xaml.vb“-Datei.
Die normale non-MVVM Variante
Um die gleich folgenden Daten anzuzeigen, nehmen wir zuerst die (vermeintlich) einfachste Variante.
Nutze nun einen der verschiedenen Wege, um einen „Loaded„-Ereignishandler für das Fenster zu generieren.
Gehe in der Code-Datei z. B. hin und wähle in der mittleren Combobox im obigen Fenster-Bereich „(MainWindow Ereignisse)“.
Dann kannst Du in der nächsten Combobox rechts daneben das passende Ereignis auswählen und Dir den Handler generieren lassen.
Nun sieht der generierte „Loaded„-Ereignishandler wie gleich folgend aus und wir können Code ergänzen.
Zuerst musst Du noch daran denken (zumindest in diesem Beispiel), dem DataGrid einen Namen zu geben.
Da wir in diesem Beispiel die Code-Behind/Non-MVVM Variante verwenden, füge den Namen im XAML-Tag hinzu:
<DataGrid Name="FilmsDataGrid" />
Damit haben wir die Möglichkeit, das WPF DataGrid in der Code-Datei anzusprechen und dessen Eigenschaften zu setzen.
Ich betone nochmal, dass dies in der Welt von WPF eigentlich nicht der bevorzugte Weg ist.
Immerhin ist diese Variante trotzdem besser, als das oben vom DataGridView bekannte „DataGridView.Rows.Add“.
Im Endeffekt möchte ich diesen Weg natürlich zeigen, um auch dieses Beispiel bereitzustellen.
Datenquelle erstellen und setzen
Damit wir dem DataGrid nun sagen können, dass es Daten anzeigen soll, sprechen wir es an.
Die Eigenschaft, Welche für uns von Interesse ist, ist die „ItemsSource„-Eigenschaft.
Bevor wir die Item-Quelle nun setzen können, müssen wir erstmal eine Art Quelle erstellen.
Verwende hierzu eine Instanz der generischen „ObservableCollection„-Klasse.
Um zu vermeiden, dass der Beitrag nachher 4000 Wörter beinhaltet, nur so viel zur Klasse, Sie ist:
- generisch – kann also mit verschiedenen Typen wie unsere Filme verwendet werden
- mitteilend – Sie kann über Änderungen (neue, oder gelöschte Einträge, etc.) Bescheid geben
- einfach – durch die für Listen übliche Funktionen ist Sie einfach zu bedienen
Der komplette Code zum Fenster sieht nun so aus:
Imports System.Collections.ObjectModel Class MainWindow Public Property Filme As ObservableCollection(Of Film) Private Sub MainWindow_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded Filme = New ObservableCollection(Of Film)() Filme.Add(New Film() With {.Titel = "Last Samurai", .Genre = "Krieg/Action", .Bewertung = 5}) Filme.Add(New Film() With {.Titel = "The Green Mile", .Genre = "Fantasy/Drama", .Bewertung = 5}) Filme.Add(New Film() With {.Titel = "Die Verurteilten", .Genre = "Drama/Krimi", .Bewertung = 5}) FilmsDataGrid.ItemsSource = Filme End Sub End Class
using System; using System.Collections.Generic; using System.Collections.ObjectModel; class MainWindow { public ObservableCollection<Film> Filme { get; set; } private void MainWindow_Loaded(object sender, RoutedEventArgs e) { Filme = new ObservableCollection<Film>(); Filme.Add(new Film() { Titel = "Last Samurai", Genre = "Krieg/Action", Bewertung = 5 }); Filme.Add(new Film() { Titel = "The Green Mile", Genre = "Fantasy/Drama", Bewertung = 5 }); Filme.Add(new Film() { Titel = "Die Verurteilten", Genre = "Drama/Krimi", Bewertung = 5 }); FilmsDataGrid.ItemsSource = Filme; } }
Zuerst instanziieren wir die Filme-Auflistung und fügen Ihr anschließend verschiedene Einträge hinzu.
Danach setzen wir die „ItemsSource“-Eigenschaft, um die Auflistung zu „binden„.
Hier siehst Du das aktuelle Ergebnis:
Die DataContext-ViewModel-Variante
Machen wir im nächsten Schritt ein Beispiel zur MVVM orientierten Variante, also mit einem Datenkontext.
Dazu müssen wir zuerst eine Klasse, also einen Bauplan anlegen, Welcher dann als Datenkontext dient.
Danach müssen wir der „DataContext„-Eigenschaft des WPF-Fensters einen Wert zuweisen.
Richtigerweise verwenden wir hier natürlich eine Instanz der folgenden Klasse:
Imports System.Collections.ObjectModel Public Class MeinMainWindowDatenkontext Public Property Filme As ObservableCollection(Of Film) Sub New() Filme = New ObservableCollection(Of Film) End Sub Public Sub LadeTestFilme() Filme.Add(New Film() With {.Titel = "Last Samurai", .Genre = "Krieg/Action", .Bewertung = 5}) Filme.Add(New Film() With {.Titel = "The Green Mile", .Genre = "Fantasy/Drama", .Bewertung = 5}) Filme.Add(New Film() With {.Titel = "Die Verurteilten", .Genre = "Drama/Krimi", .Bewertung = 5}) End Sub End Class
using System; using System.Collections.ObjectModel; public class MeinMainWindowDatenkontext { public ObservableCollection<Film> Filme { get; set; } public MeinMainWindowDatenkontext() { Filme = new ObservableCollection<Film>(); } public void LadeTestFilme() { Filme.Add(new Film() { Titel = "Last Samurai", Genre = "Krieg/Action", Bewertung = 5 }); Filme.Add(new Film() { Titel = "The Green Mile", Genre = "Fantasy/Drama", Bewertung = 5 }); Filme.Add(new Film() { Titel = "Die Verurteilten", Genre = "Drama/Krimi", Bewertung = 5 }); } }
Den Code der Form würden wir dann so anpassen:
Class MainWindow Private Sub MainWindow_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded Dim datenKontext = New MeinMainWindowDatenkontext() datenKontext.LadeTestFilme() DataContext = datenKontext End Sub End Class
class MainWindow { private void MainWindow_Loaded(object sender, RoutedEventArgs e) { var datenKontext = new MeinMainWindowDatenkontext(); datenKontext.LadeTestFilme(); DataContext = datenKontext; } }
Den XAML-Code müssen wir letztendlich auch noch anpassen.
<Window x:Class="MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:WpfDataGridExampleVB" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800"> <Grid> <DataGrid ItemsSource="{Binding Filme}" /> </Grid> </Window>
Damit sagen wir dem Fenster, bzw. genauer genommen dem DataGrid: „Hey, deine Items findest Du in der Datenkontext-Eigenschaft namens Filme„
Fazit
Am Ende unseres heutigen Beitrages angekommen, lassen wir die wichtigsten Aspekte nochmal aufleuchten.
Zusammengefasst ist das WPF DataGrid ein modernes Steuerelemente, Welches die Darstellung von tabellarischen Daten unterstützt.
Das Steuerelement kann auf viele Arten und Weisen den eigenen Bedürfnissen angepasst werden.
Im heutigen Beitrag habe ich Dir gezeigt, wie Du Daten auf View-Basis anzeigst.
Danach haben wir uns die etwas modernere Variante mit Hilfe eines ViewModels angeschaut.
Moderne Anwendungen verwenden besonders in Kombination mit WPF eigentlich nur noch das MVVM-Entwurfsmuster.
Geplante Erweiterungen
Für diesen Beitrag habe ich in Zukunft noch folgende eventuelle Beispiele geplant:
- Mehr Fokus auf Styling
- Arbeit mit Datensätzen
- Ähnliches..