DataGridView Special 1: Anschauliche Daten - numerische Spalten auf Images abbilden

11. März 2010 von Werner Mager · Gelesen: 1042 · heute: 4

In diesem Special möchte auf ein paar Tricks und Kniffe eingehen, mit denen man aus dem Standard-Control DataGridView noch mehr herausholen kann. Im ersten Teil wird gezeigt, wie numerische Spalten clientseitig auf Images abgebildet werden können. Ganz nebenbei wird in die Benutzung von ADO.Net, SQL-Serverdateien und typisierten Datasets eingeführt.

In Datenbanken werden Attribute in der Regel numerisch gespeichert. Ein Ampelstatus kann beispielsweise auf Rot=0, Gelb=1 und Grün = 2 abgebildet werden. In einer netten Windowsanwendung wollen User jedoch statt der Zahlen eine grafische Darstellung. In diesem Artikel wird aufgezeigt, wie dies mit einem DataGridView möglich ist, ohne dass die Bilder in der Datenbank abgelegt werden müssen.

Ampelstatus

Die Cruz mit der Image-Spalte
Auf den ersten Blick scheint die eingangs beschriebene Situation gar nicht so kompliziert zu sein. In einem DataGridView können Spalten vom Typ “DataGridViewImageColumn” angelegt werden.
Aber ab hier beginnen die Probleme. Die neu angelegte Spalte erwartet eine Datenquelle, die Objekte vom Typ “Image” bereitstellt. Eine Anbindung an eine Datenquelle mit numerischen Werten oder gar mit String-basierten Schlüsseleinträgen ist nicht vorgesehen. Auch die naheliegende Möglichkeit, eine ImageList anzufügen, sucht man vergebens.

Der Trick mit dem Expression-Attribut
Es gibt aber doch einen relativ kompakten und zugleich performanten Weg, wie man die Daten clientseitig auf Images abbilden kann. Der Trick hierbei ist, eine weitere Tabelle in das Dataset hinzuzufügen, durch die die Schlüssel-Image Zuordnung realisiert wird. Die clientseitige Tabelle, an die das DataGridView gebunden wird, muss um eine Spalte mit dem Datentyp Image erweitert werden. Diese wird jedoch nicht aus der Datenbank gefüllt, sondern über eine Relation mit der Schlüssel-Image Tabelle verknüpft. Über das Attribut “Expression” erfolgt schließlich die Verknüpfung. Soweit zur Theorie, die Praxis folgt sogleich.

Ampelstatus als praktisches Beispiel
In einem kleinen Beispiel soll das Vorgehen verdeutlicht werden. Dabei kommen ausschließlich typisierte Datasets zum Einsatz, das Vorgehen lässt sich aber natürlich auch auf untypisierte Daten übertragen. Als Ausgangsbasis dient ein Visual Studio Projekt, das z.B. “DataGridViewSpecialPart1″ heißen könnte. Dabei ist es wichtig, dass das Visual Studio mit Administratorrechten gestartet wird. Unter Windows Vista und Windows 7 muss das Visual Studio durch einen Rechtsklick und “Als Administrator starten…” aufgerufen werden.

Eine SQL Datenbank anlegen
Für unser Beispiel wird die Datenbank als mdf gespeichert und bei Bedarf in den SQL-Server eingeklingt. Dies ist die optimale Lösung für Entwicklung. Parktischer Weise bring Visual Studio bereits den SQL Server Express mit, so dass neben einer Standardinstallation von Visual Studio 2008 keine weitere Software benötigt wird, um dieses Beispiel nachzuvollziehen zu können. Es kann natürlich statt der dateibasierten (”attached”) Datenbank eine “normale” Datenbank eingebunden werden.
Mit folgenden einfachen Schritten wird die Datenbank direkt aus dem Visual Studio heraus angelegt:

  • Menu Daten => neue Datenquelle zufügen. “Datenbank” auswählen
  • Im “Assistent zum Konfigurieren von Datenquellen” auf “Neue Verbindung” klicken
  • “Microsoft SQL Server-Datenbankdatei” auswählen
  • Als Name der Datenbankdatei z.B. “DataGridViewSpecialPart1″ angeben.

Mit dem Klick auf “OK” wird die Datei angelegt und in den lokalen SQL-Server eingehängt und man landet wieder im “Assistent zum Konfigurieren von Datenquellen”. Jetzt sind eigentlich nur noch ein paar Standard-Abfragen zu bestätigen, bei denen eigentlich keine weiteren Änderungen nötig sind:

  • Nach dem Klick auf “Weiter” und man wird gefragt, ob die Datenbankdatei im Visual Studio Projekt gespeichert werden soll. Hier sollte “ja” gewählt werden, damit alles beisammen ist.
  • Schließlich kommt noch die Frage, wo der Connectstring gespeichert werden soll, aber auch hier empfiehlt es sich, die Standardeinstellungen beizubehalten.
  • Die letzte Maske schließlich dient dazu, ein DataSet in dem Projekt anzulegen. Dies ist die Clientseitige Entsprechung zu unserer Datenbank. Hier einfach auf “Fertigstellen” klicken.

Für alle, die sich in diesem Endlos-Wizard verirrt haben sollten, habe ich ein Walk Through in Form von Screenshots vorbereitet:
Walk Through Neue Datenquelle

Im Projektmappen-Explorer erscheinen nun zwei neue Elemente in unserem Projekt:

  • DataGridViewSpecialPart1.mdf : Die Serverseitige SQL-Datenbank
  • DataGridViewSpecialPart1DataSet.xsd : Die Clientseitige Entsprechung der Datenbank

Projektmappen-Explorer mit Datenbank

Eine einfache Datenbank: Projektverwaltung
Für unser Beispiel benötigen wir nur eine Tabelle, die “Projects” heißen soll. Jede Zeile wird dabei ein Projekt repräsentieren. Diese Tabelle muss zunächst Serverseitig angelegt werden. Dazu wird ein Doppelklick auf die “DataGridViewSpecialPart1.mdf” gemacht, und der Server-Explorer öffnet sich. Im Baum ist der Knoten “Tabellen” auszuwählen, dann ein Rechtsklick “Neue Tabelle hinzufügen”.
Die Tabelle soll nun drei Spalten IDProject, Name und Status erhalten:

Die Tabelle Projects

Die Spalte IDProjekt wird als Primärschlüssel markiert und in den Eigenschaften der Spalte unter “Identitätsspezifikation” wird “(Ist Identity)” auf “ja” gesetzt. Dadurch wird die ID der einzelnen Projekte automatisch hochgezählt.

Identitätsspezifikation

Wird nun auf “Speichern” geklickt, fragt Visual Studio, wie die Tabelle heißen soll, und wir können ihr nun den Namen “Projects” geben.

Das Ado.Net Gegenstück : ein (typsiertes) DataSet
Die im vorherigen Schritt angelegte Datenbank wird in der Ado.Net Welt durch ein typisiertes DataSet repräsentiert. Typisiert bedeutet dabei, dass für jede Datenbank und jede Tabelle eine spezielle Klasse (abgeleitet von DataSet und DataTable) angelegt wird, die genau an den Aufbau der Datenbank angepasst ist. Beim Programmieren muss man dann gar nicht mehr über den Aufbau einzelner Tabellen nachdenken, über IntelliSense kann man direkt auf Eigenschaften zugreifen, die den einzelnen Spalten zugeordnet sind. Aber genug der Theorie, denn die Praxis ist ganz einfach:

  • Über einen Doppelklick wird das “DataGridViewSpecialPart1DataSet.xsd” geöffnet.
  • Aus dem Serverexplorer wird nun die Tabelle “Projects” in das DataSet gezogen.

Automatisch generierte lokale Tabelle

In den folgenden Schritten wird im Dataset eine zusätzliche (lokale) Tabelle angelegt, die die Images aufnehmen wird. Über eine Relation werden diese mit den Daten aus der Datenbank verknüpft und im DataGridView angezeigt.

Eine Tabelle voll Bilder
In dem Designer wird nun zunächst eine weitere Tabelle “StatusImages” angelegt. Dies kann z.B. durch Drag & Drop einer DataTable aus der Toolbox auf das DataSet erfolgen. Diese Tabelle existiert somit nur innerhalb der Anwendung (Clientseitig) und nicht in der Datenbank.
Über einen Rechtsklick werden der DataTable die zwei Spalten IDStatus und ImageValue zugefügt:

Lokale Tabelle StatusImages

In dem Eigenschaften-Fenster muss für die Spalten noch jeweils der Datentyp festgelegt werden. Hier ist für IDStatus int32 zu wählen, und für ImageValue ist System.Drawing.Bitmap einzugeben. Die IDStatus-Spalte ist zudem als Primärschlüssel zu definieren, dies geht über einen Rechtsklick.
Die Eigenschaft “DataType” wird dabei über das Eigenschaften-Fenster festgelegt.
Die Bilder für die Tabelle werden in den Projekt-Resourcen abgelegt. Diese finden sich im Projektmappen-Explorer unter Properties/Resources.resx.
In den Resourcen wird links oben auf die Ansicht “Bilder” gewechselt und die drei Bilder per Copy & Paste eingefügt.

Die lieben Verwandten: Relations
Nun muss die Tabelle StatusImages noch mit der Tabelle Projects verbunden werden. Dazu wird im Designer eine Relation hinzugefügt (z.B. aus der Toolbox auswählen). Die Tabelle “StatusImages” wird als Übergeordnete Tabelle ausgewählt, die Tabelle “Projects” als Untergeordnete Tabelle.

Relation

Im DataSet erscheint die Relation nun als Verbindung zwischen den Tabellen:

Relation zwischen den Tabellen

Bleibt die Frage, wie die Bilder in die clientseitige Tabelle Projects kommen. Hierzu wird ein bisschen Magic benötigt. Zuerst fügen wir eine weitere Spalte “StatusImage” mit dem Datentyp System.Drawing.Bitmap an die Tabelle an. Die Tabelle Projects enthält nun sowohl an die Datenbank gebundene spalten als auch eine ungebundene Spalte. Damit in dieser die Bilder zu dem jeweiligen Status erscheinen, wird die Eigenschaft “Expression” benutzt. Hier wird folgender Text eingegeben:
Parent(StatusImages_Projects).ImageValue
In der Klammer steht dabei der Name der Relation, über die die verbundene Tabelle erreicht werden kann. Mit dem Punkt wird schließlich die gewünschte Spalte in der verbundenen Tabelle adressiert. Hierbei müssen die Datentypen natürlich passen.

Visualisieren des DataSets
Schließlich muss das DataGridView noch auf das Formular gebracht werden. Dazu ist jedoch nicht die Toolbox zu verwenden, sondern aus der Lasche Datenquellen wird einfach die gesamte Tabelle “Projects” auf das Formular gezogen. Der Designer legt dabei automatisch ein DataGridView an. Dieses wird über die Funktion “Im übergeordneten Container andocken” zum Füllen des Fensters gebracht.
Als letzten Schritt sind noch drei Zeilen Code in die Datei Form1.cs zu schreiben, um die Bilder aus den Resourcen in die Tabelle “StatusImage” zu übertragen:

using DataGridViewSpecialPart1.Properties;
public Form1()
        {
            InitializeComponent();
            dataGridViewSpecial1DataSet.StatusImages.AddStatusImagesRow(0, Resources.red);
            dataGridViewSpecial1DataSet.StatusImages.AddStatusImagesRow(1, Resources.yellow);
            dataGridViewSpecial1DataSet.StatusImages.AddStatusImagesRow(2, Resources.green);
}

Zu guter Letzt
Damit ist unser Projekt auch schon fertig. Daten, die in die Anwendung eingeben werden, werden nun direkt in der SQL-Datenbank gespeichert. Wird der Wert in der Spalte “Status” geändert, erscheint automatisch das passende Bild in der letzten Spalte. Natürlich lässt sich das hier vorgestellte Verfahren auch auf lokale DataSets anwenden, ohne dass eine Datenbank verwendet werden muss.

Wie immer stelle ich an dieser Stelle das komplette Projekt zum Download bereit:
Visual Studio Pojekt “DataGridViewSpecialPart1″

Ich freue mich schon auf die nächsten Specials, in denen ich euch noch ein paar mehr Tricks aus der ADO.Net Welt verraten werde.

Hinterlasse eine Antwort