Einführung eines neuen Datenrasters

Veröffentlicht: 13. Mai 2005
Von Matthew MacDonald

Visual Studio .NET Developer

Das neue "DataGridView"-Steuerelement ist die .NET 2.0-Antwort auf das in .NET 1.x standardmäßige, aber reichlich leistungsschwache "DataGrid"-Steuerelement. Zu den vielen Verbesserungen von "DataGridView" gehören umfassende Anpassungs- und detaillierte Formatierungsmöglichkeiten, flexible Skalierung und Auswahl, höhere Leistung und ein umfassenderes Ereignismodell.

Die beiden ersten Versionen des .NET Framework (.NET 1.0 und .NET 1.1) wiesen in Bezug auf die Datenbindung ein eklatantes Defizit auf. Zwar stand den Entwicklern ein flexibles, konfigurierbares Modell zur Verfügung, mit dem sie fast jedes Steuerelement mit nahezu jeder Datenquelle verknüpfen konnten, doch gab es kein praktisches Verfahren zum Anzeigen vollständiger Datentabellen. Das einzige für diesen Zweck geeignete Tool war das DataGrid-Steuerelement, das bei einfachen Demonstrationen gut funktionierte, für realistischen Code jedoch wenig geeignet war.

Eines der Hauptziele von .NET 2.0 ist es, diesen Mangel zu beheben. Microsoft hat diese Herausforderung mit dem völlig neuen DataGridView-Steuerelement angenommen. Für DataGridView gelten zwei Leitprinzipien. Erstens soll es gängige Aufgaben wie die Erstellung von Master-Detail-Listen, Überprüfung und Datenformatierung so unterstützen, dass Sie lediglich einige wenige Codezeilen schreiben müssen. Vor allem aber ist es von Anfang an mit Blick auf eine Erweiterbarkeit konzipiert, damit Sie die Funktionen integrieren können, die Sie benötigen, ohne bei der Programmierung in tiefere Codeschichten eingreifen oder Tricks anwenden zu müssen.

Grundlegende Datenbindung

Am besten machen Sie sich mit dem DataGridView vertraut, wenn Sie es ausprobieren, ohne dabei eine einzige Eigenschaft zu konfigurieren. Ebenso wie beim DataGrid können Sie ein DataTable-Objekt (oder ein von DataTable abgeleitetes Objekt) mithilfe der DataSource-Eigenschaft binden.

Dim ds As DataSet = GetDataSet()
DataGridView1.DataSource = ds.Tables("Customers")

Im Unterschied zum DataGrid kann das DataGridView immer nur eine Tabelle anzeigen. Wenn Sie ein ganzes DataSet binden, werden Daten nur dann angezeigt, wenn Sie für die DataMember-Eigenschaft den Namen der anzuzeigenden Tabelle festlegen.

DataGridView1.DataSource = ds
DataGridView1.DataMember = "Customers"

Die grundlegende DataGridView-Darstellung folgt wenigen einfachen Regeln:

  • Für jedes Feld in der Datenquelle wird eine Spalte erstellt.

  • Spaltenüberschriften werden mithilfe der Feldnamen erstellt. Die Spaltenüberschriften sind fixiert, der Benutzer verliert sie daher nie aus dem Blick, wenn er sich weiter unten in der Liste bewegt.

  • Die Darstellungsstile von Windows XP werden unterstützt. Die Spaltenheader sind modern gestaltet und werden hervorgehoben, wenn der Benutzer die Maus über sie bewegt.

Zum DataGridView gehören außerdem zahlreiche Standards, die Ihnen eventuell nicht sofort auffallen:

  • Es ermöglicht das direkte Bearbeiten. Der Benutzer kann in eine Zelle doppelklicken oder auf F2 drücken, um den aktuellen Wert zu bearbeiten. Dies gilt jedoch nicht für Felder, für die DataColumn.ReadOnly auf TRUE gesetzt ist (wie etwa das Feld OrderID im aktuellen Beispiel).

  • Es unterstützt das automatische Sortieren. Der Benutzer kann einmal oder zweimal auf einen Spaltenheader klicken, um die Werte des betreffenden Feldes in aufsteigender bzw. absteigender Reihenfolge zu sortieren. Der Datentyp wird bei der Sortierung automatisch berücksichtigt, es wird also alphabetisch oder numerisch sortiert. Bei alphabetischen Sortierungen wird zwischen Klein- und Großschreibung unterschieden.

  • Es lässt verschiedene Arten zum Markieren zu. Die Benutzer können eine oder mehrere Zellen bzw. mehrere Zeilen durch Klicken und Ziehen markieren. Durch Klick auf das Rechteck oben links im DataGridView wird die gesamte Tabelle ausgewählt.

  • Es unterstützt eine automatische Skalierung. Wenn die Benutzer auf die Spaltentrennlinie zwischen den Überschriften doppelklicken, wird die Spalte auf der linken Seite je nach dem Inhalt der Zellen automatisch breiter oder schmaler.

Verbessern des "DataGridView"-Erscheinungsbildes

Das Erscheinungsbild des DataGridView-Steuerelements wurde in der Standardeinstellung gegenüber dem DataGrid-Steuerelement nur wenig verbessert. Doch schon wenige kleine Änderungen reichen aus, um es deutlich zu verbessern.

Ein Problem ist, dass sich die Spaltenbreite nicht automatisch den Daten anpasst. Sie können dieses Problem mit der DataGridView.AutoSizeColumns()-Methode lösen, indem Sie einen der Werte der DataGridViewAutoSizeColumnCriteria-Enumeration verwenden. Sie können die Spaltenbreite an der Breite der Spaltenüberschrift, an den aktuell angezeigten Zeilen oder an allen Zeilen in der Tabelle ausrichten.

' Resize columns based on the width of the largest 
' piece of text in a header or one of the rows for 
' this column.
DataGridView1.AutoSizeColumns( _
  DataGridViewAutoSizeColumnCriteria.HeaderAndRows)

Diese Methode lässt sich erst aufrufen, nachdem Sie die Daten gebunden haben; andernfalls ist sie wirkungslos. Es empfiehlt sich außerdem, sie nach der Bearbeitung durch die Benutzer einzusetzen (eventuell als Reaktion auf ein Ereignis wie
DataGridView.CellValueChanged).

Anstatt die Spaltenbreite anzupassen, können Sie auch die Zeilenhöhe ändern. Normalerweise wird der Text in einer Spalte in mehrere Zeilen umbrochen. Wenn Sie die DataGridView.AutoSizeRows()-Methode verwenden, wird die Zeilenhöhe dem Inhalt angepasst. Bevor Sie diese Methode nutzen, sollten Sie die Spaltenbreite vergrößern, insbesondere wenn Felder vorhanden sind, die sehr viel Text enthalten. Mit dem folgenden Codeausschnitt wird beispielsweise die Breite der Spalte Description vervierfacht und anschließend die Zeilenhöhe dem Inhalt angepasst.

DataGridView.Columns("Description").Width *= 4
DataGridView.AutoSizeRows( _
  DataGridViewAutoSizeRowsMode.HeaderAndColumnsAllRows)

In Abbildung 1 werden die verschiedenen Ansätze zur automatischen Größenanpassung des DataGridView-Steuerelements verglichen.

Ansätze zur automatischen Größenanpassung des DataGridView-Steuerelements
Abbildung 1

Eine weitere sinnvolle Änderung ist die Bereinigung des in den einzelnen Spalten angezeigten Überschriftentexts. Der Titel Order Date sieht professioneller aus als der Feldname OrderDate. Diese Änderung ist relativ einfach. Aus der DataGridView.Columns-Auflistung müssen Sie lediglich die entsprechende DataGridViewColumn abrufen und deren HeaderText-Eigenschaft ändern:

DataGridView.Columns("OrderID").HeaderText = "Order ID"

Auswählen von Zellen mit dem DataGridView-Steuerelement

Das DataGridView-Steuerelement schränkt in der Standardeinstellung die Auswahl von Elementen nicht ein. Die Benutzer können einzelne Zellen, Gruppen von Zellen und alle Zellen auf einmal markieren (durch Klicken auf das Rechteck oben links im Raster) bzw. eine oder mehrere Zeilen markieren (durch Klicken auf die Zeilenüberschriftenspalte). Je nach Auswahlmodus haben die Benutzer außerdem die Möglichkeit, eine oder mehrere Spalten durch Klicken auf die Spaltenüberschriften auszuwählen. Sie können dieses Verhalten steuern, indem Sie für die DataGridView.SelectionMode-Eigenschaft einen der Werte aus der DataGridViewSelectionMode-Enumeration festlegen, die im Folgenden beschrieben werden:

  • CellSelect Die Benutzer können Zellen auswählen, jedoch keine ganzen Zeilen oder Überschriften. Die Benutzer können mehrere Zellen auswählen, wenn DataGridView.MultiSelect den Wert TRUE hat.

  • FullColumnSelect Die Benutzer können nur ganze Spalten auswählen, indem sie auf die Spaltenüberschrift klicken. Die Benutzer können mehrere Spalten auswählen, wenn DataGridView.MultiSelect den Wert TRUE hat. In diesem Modus wird das Raster durch Klicken auf einen Spaltenheader nicht sortiert.

  • FullRowSelect Die Benutzer können nur ganze Zeilen auswählen, indem sie auf den Zeilenheader klicken. Die Benutzer können mehrere Zeilen auswählen, wenn DataGridView.MultiSelect den Wert TRUE hat.

  • ColumnHeaderSelect Die Benutzer können die Auswahlmodi CellSelect oder FullColumnSelect verwenden. In diesem Modus wird das Raster durch Klicken auf einen Spaltenheader nicht sortiert.

  • RowHeaderSelect Die Benutzer können die Auswahlmodi CellSelect oder FullRowSelect verwenden. Dies ist der Standardauswahlmodus.

Das DataGridView-Steuerelement vereinfacht das Abrufen der ausgewählten Zellen mithilfe von drei Eigenschaften: SelectedCells, SelectedRows und SelectedColumns. SelectedCells gibt unabhängig von dem verwendeten Auswahlmodus stets eine Auflistung von DataGridViewCell-Objekten zurück. SelectedRows gibt dagegen nur dann Informationen zurück, wenn durch Klicken auf die Zeilenüberschrift eine ganze Zeile ausgewählt wurde, während SelectedColumns nur dann Informationen zurückgibt, wenn durch Klicken auf die Spaltenüberschrift eine ganze Spalte ausgewählt wurde.

Der folgende Codeausschnitt prüft, ob ganze Zeilen ausgewählt sind. Sobald eine Zeile gefunden wird, wird der entsprechende Wert für die Spalte CustomerID in einer Meldung angezeigt:

For Each SelectedRow As DataGridViewRow In _
  DataGridView1.SelectedRows
    MessageBox.Show( _
      SelectedRow.Cells("CustomerID").Value)
Next

Ebenso einfach ist es, einen Verweis auf die aktuelle Zelle mit den Eigenschaften CurrentCell oder CurrentCellAddress abzurufen. Beim Arbeiten mit dem DataGridView-Steuerelement werden Sie feststellen, dass die aktuelle Zelle eine Fokusumrahmung aufweist, ein Rechteck aus schwarzen Punkten. Dies ist die aktuelle Position des Benutzers.

Die CurrentCellAddress-Eigenschaft ist schreibgeschützt. Sie können die aktuelle Position mit CurrentCell jedoch programmgesteuert ändern. In diesem Fall wird im DataGridView-Steuerelement ein Bildlauf ausgeführt, so dass die aktuelle Position sichtbar wird.

' Move to the fourth cell in the eleventh row.
DataGridView.CurrentCell = _
  DataGridView.Rows(10).Cells(3)

Die "DataGridView"-Objekte

Bisher haben Sie gesehen, wie Sie mit den aktuell ausgewählten Zeilen, Zellen und Spalten arbeiten können. Das DataGridView-Steuerelement enthält zwei wesentliche Auflistungen, die das Bearbeiten sämtlicher Daten ermöglichen. Sie heißen Columns (eine Auflistung von DataGridViewColumn-Objekten) und Rows (eine Auflistung von DataGridViewRow-Objekten; beide Auflistungen verweisen auf eine Auflistung von DataGridViewCell-Objekten).
Abbildung 2 zeigt das Objektmodell.

Objektmodell
Abbildung 2

Das DataGridViewColumn-Objekt dient im Allgemeinen zum Konfigurieren von Eigenschaften für die Spaltenanzeige, Formatierungen und Spaltenüberschriften. Mit den Objekten DataGridViewRow und DataGridViewCell rufen Sie die eigentlichen Daten aus dem gebundenen Datensatz ab. Wenn Sie die Daten in einer DataGridViewCell ändern, so entspricht dies einer Bearbeitung durch den Benutzer: Die entsprechenden DataGridView-Änderungsereignisse werden ausgelöst und die zugrunde liegende DataTable wird geändert.

Nachdem Sie das DataGridView-Objektmodell kennen gelernt haben, können Sie nun ohne weiteres Code erstellen, der die Tabelle iterativ durchläuft. Zum Auswählen einer Zeile, Spalte oder Zelle müssen Sie lediglich das entsprechende DataGridViewRow-, DataGridViewColumn- oder DataGridViewCell-Objekt suchen und die IsSelected-Eigenschaft auf TRUE setzen.

Im folgenden Beispiel werden programmgesteuert alle Zeilen ausgewählt, deren Feld OrderID einen Wert von weniger als 100 enthält:

For Each Row As DataGridViewRow In DataGridView1.Rows
    If Row.Cells("OrderID").Value < 100 Then
        Row.Selected = True
    End If
Next

Von DataGridViewColumn werden verschiedene Klassen abgeleitet. Diese Klassen können die Darstellung und Bearbeitung von Werten in einer Zelle steuern. .NET umfasst fünf vordefinierte DataGridViewColumn-Klassen: DataGridViewButtonColumn, DataGridViewCheckBoxColumn, DataGridViewComboBoxColumn, DataGridViewImageColumn und DataGridViewTextBoxColumn.

"DataGridView"-Formate

Eine der Herausforderungen bei der Konzeption des DataGridView-Steuerelements war die Erstellung eines Formatierungssystems, das so flexibel ist, dass es unterschiedliche Formatierungsebenen anwenden kann, gleichzeitig jedoch auch bei sehr großen Tabellen effizient bleibt. Unter dem Gesichtspunkt der Flexibilität ist es am besten, wenn der Entwickler jede Zelle individuell konfigurieren kann. In Bezug auf die Effizienz kann dieser Ansatz jedoch katastrophale Folgen haben. Eine Tabelle mit Tausenden von Zeilen enthält Zehntausende von Zellen, und bei der Verwaltung unterschiedlicher Formatierungen für jede einzelne Zelle wird mit Sicherheit sehr viel Arbeitsspeicher verschwendet.

Zur Lösung dieses Problems gibt es für das DataGridView-Steuerelement ein mehrschichtiges Modell, bei dem DataGridViewCellStyle-Objekte eingesetzt werden. Ein DataGridViewCellStyle-Objekt stellt das Format einer Zelle dar und umfasst Eigenschaften wie Farbe, Schriftart, Ausrichtung, Umbruch und Datenformatierung. Sie können ein einzelnes DataGridViewCellStyle erstellen, um die Standardformatierung für eine ganze Tabelle festzulegen. Zusätzlich können Sie die Standardformatierung für eine Spalte, eine Zeile und eine einzelne Zelle festlegen. Je detaillierter die Formatierung ist und je mehr DataGridViewCellStyle-Objekte Sie erstellen, desto weniger skalierbar ist die Lösung. Wenn Sie jedoch überwiegend eine spalten- und zeilenbasierte Formatierung verwenden und nur gelegentlich einzelne Zellen formatieren, benötigt das DataGridView-Steuerelement nicht wesentlich mehr Arbeitsspeicher als das DataGrid-Steuerelement.

Bei der Anwendung der Formatierung durch das DataGridView-Steuerelement gelten folgende Prioritätsstufen (absteigend geordnet):

  1. 1. DataGridViewCell.Style

  2. 2. DataGridViewRow.DefaultCellStyle

  3. 3. DataGridView.AlternatingRowsDefaultCellStyle

  4. 4. DataGridView.RowsDefaultCellStyle

  5. 5. DataGridViewColumn.DefaultCellStyle

  6. 6. DataGridView.DefaultCellStyle

Es ist wichtig zu verstehen, dass die Formatobjekte nicht so angewendet werden, dass alle übrigen Formatierungen ausgeschlossen sind. Das DataGridView-Steuerelement überprüft vielmehr jede einzelne Eigenschaft. Angenommen, in einer Zelle wird mit der DataGridViewCell.Style-Eigenschaft eine benutzerdefinierte Schriftart angewendet, aber keine benutzerdefinierte Vordergrundfarbe festgelegt. Die Schrifteinstellung setzt also die Schriftartinformationen in anderen Formatobjekten außer Kraft, die Vordergrundfarbe wird jedoch vom nächsten Formatobjekt in der Hierarchie (in diesem Fall DataGridViewRow.DefaultCellStyle) geerbt, falls dieses nicht den Wert NULL hat.

Das DataGridViewCellStyle-Objekt definiert zwei Arten von Formatierung: Daten und Darstellung. Die Datenformatierung bestimmt, wie der datengebundene Wert geändert wird, bevor er dargestellt wird. Dabei werden Zahlen- oder Datumswerte in der Regel durch Formatierungszeichenfolgen in Text umgewandelt. Für die Datenformatierung legen Sie mit der DataGridViewCellStyle.Format-Eigenschaft einfach den Formatbezeichner oder die benutzerdefinierte Formatzeichenfolge fest.

Mit dem folgenden Codeausschnitt werden beispielsweise alle Zahlen im Feld UnitCost so formatiert, dass sie als Währungswerte mit zwei Dezimalstellen und dem in den Gebietsschemaeinstellungen definierten Währungssymbol dargestellt werden:

DataGridView1.Columns("UnitCost"). _
  DefaultCellStyle.Format = "C"

Die Darstellungsformatierung umfasst "kosmetische" Details wie Farbe und Schriftart. Mit dem folgenden Code wird bspw. der Text im Feld UnitCost nach rechts ausgerichtet, die Schrift wird fett dargestellt und der Zellenhintergrund gelb.

DataGridView1.Columns("UnitCost"). _
  DefaultCellStyle.Font = _
  New Font(DataGridView.Font, FontStyle.Bold)
DataGridView1.Columns("UnitCost"). _
  DefaultCellStyle.Alignment = _
  DataGridViewContentAlignment.MiddleRight
DataGridView1.Columns("UnitCost"). _
  DefaultCellStyle.BackColor = Color.LightYellow

Weitere formatierungsbezogene Eigenschaften sind ForeColor, SelectionForeColor, SelectionBackColor, WrapMode (bestimmt, ob Text in mehrere Zeilen umbrochen wird, falls genügend Platz ist, oder ob er einfach abgeschnitten wird) und NullValue (ein Wert, der für Nullwerte eingesetzt wird).

Das DataGridView-Steuerelement umfasst einen Designer, mit dem Sie zur Entwurfszeit Spaltenformate konfigurieren können. Klicken Sie im Fenster Properties (Eigenschaften) auf die Verknüpfung DataGridView Properties (Eigenschaften von DataGridView) oder wählen Sie AutoFormat, um unter verschiedenen vordefinierten Formateinstellungen zu wählen.

Benutzerdefinierte Zellenformatierung

Bei der Formatierung von Zellen arbeiten Sie zunächst mit den höheren DataGridView-, DataGridViewColumn- und DataGridViewRow-Eigenschaften. Gelegentlich müssen Sie jedoch das Format für einzelne Zellen festlegen. Beispielsweise möchten Sie die Daten in einer Spalte kennzeichnen, falls sie einen bestimmten Wert unter- oder überschreiten. Ein Beispiel hierfür ist die Hervorhebung von abgelaufenen Fälligkeitsdaten in einer Projektplanliste oder negative Renditen in einer Verkaufsanalyse. In beiden Fällen müssen Sie die einzelne Zelle formatieren.

Da Sie das DataGridView-Objektmodell bereits kennen, versuchen Sie eventuell, sämtliche Zellen in einer bestimmten Spalte nach den Werten zu durchsuchen, die Sie hervorheben möchten. Dieser Ansatz funktioniert zwar, ist jedoch nicht optimal. Das Hauptproblem dabei: Wenn der Benutzer die Daten bearbeitet oder wenn die gebundene Datenquelle durch Ihren Code geändert wird, wird die Hervorhebung der Zelle nicht entsprechend angepasst.

Glücklicherweise stellt das DataGridView-Steuerelement genau für diesen Zweck ein CellFormatting-Ereignis bereit. CellFormatting wird unmittelbar vor der Darstellung des Zellenwerts ausgelöst. Damit erhalten Sie die Möglichkeit, das Zellenformat auf Grundlage des Inhalts der Zelle zu aktualisieren. Im folgenden Beispiel wird nach einem bestimmten Kunden gesucht und die Zelle dementsprechend gekennzeichnet:

Private Sub DataGridView1_CellFormatting( _
  ByVal sender As System.Object, _
  ByVal e As System.Windows.Forms. _
  DataGridViewCellFormattingEventArgs) _
  Handles DataGridView1.CellFormatting

    ' Check if this is the right column.
    If DataGridView1.Columns(e.ColumnIndex).Name = _
      "CustomerID" Then
        ' Check if this is the right value.
        If e.Value = "ALFKI" Then
            e.CellStyle.ForeColor = Color.Red
            e.CellStyle.BackColor = Color.Yellow
        End If
    End If
End Sub

Nicht nur Formate beeinflussen das Erscheinungsbild des Rasters. Sie haben auch die Möglichkeit, Spalten auszublenden, sie zu verschieben und zu "fixieren", so dass sie sichtbar bleiben, auch wenn der Benutzer einen Bildlauf nach rechts ausführt. All diese Möglichkeiten werden durch die Eigenschaften der DataGridViewColumn-Klasse bereitgestellt und werden im Folgenden beschrieben:

  • DisplayIndex Legt fest, an welcher Position die Spalte im DataGridView angezeigt wird. Beispielsweise wird eine Spalte, deren DisplayIndex den Wert 0 (null) hat, automatisch ganz links angezeigt. Haben mehrere Spalten denselben DisplayIndex, wird die Spalte, die in der Auflistung an erster Stelle steht, zuerst angezeigt. Wenn Sie mit dem DisplayIndex eine Spalte nach links verschieben, müssen Sie unter Umständen also auch den DisplayIndex der Spalte ganz links festlegen, damit sie nach rechts verschoben wird. Anfangs entspricht der DisplayIndex dem Index des DataGridViewColumn-Objekts in der DataGridView.Columns-Auflistung.

  • Frozen Wenn diese Eigenschaft den Wert TRUE hat, bleibt die Spalte auf der linken Seite der Tabelle sichtbar und fixiert, auch wenn der Benutzer einen Bildlauf nach rechts ausführt, um weitere Spalten anzuzeigen.

  • HeaderText Legt den Text für den Spaltenheader fest.

  • Resizable und MinimumWidth Setzen Sie Resizable auf FALSE, um zu verhindern, dass der Benutzer die Größe einer Spalte ändert, oder setzen Sie MinimumWidth auf die zulässige Mindestanzahl von Pixeln.

  • Visible Setzen Sie diese Eigenschaft auf FALSE, um eine Spalte auszublenden.

Schaltflächenspalten

Einer der in DataGridView verfügbaren Spaltentypen ist DataGridViewButtonColumn, mit dem neben jedem Element eine Schaltfläche angezeigt wird. Sie können auf das Klicken auf diese Schaltfläche reagieren und eine andere Aktion starten oder ein neues Formular anzeigen.

Im folgenden Beispiel wird eine einfache Schaltflächenspalte mit dem Schaltflächentext Details... erstellt:

' Create a button column.
Dim Details As New DataGridViewButtonColumn()
Details.Name = "Details"

' Turn off data-binding and show static text.
' (You could use a property from the table by setting
' the DataPropertyName property instead.)
Details.DisplayTextAsFormattedValue = False
Details.Text = "Details..."

' Clear the header.
Details.HeaderText = ""

' Add the column.
DataGridView1.Columns.Insert( _
  DataGridView1.Columns.Count, Details)

Abbildung 3 zeigt das Raster mit der neuen Spalte. Der folgende Code reagiert auf das Klicken auf eine Schaltfläche in einer beliebigen Zeile und zeigt die entsprechenden Datensatzinformationen an:

Raster mit neuer Spalte
Abbildung 3

Private Sub DataGridView1_CellClick( _
  ByVal sender As System.Object, _
  ByVal e As System.Windows.Forms. _
  DataGridViewCellEventArgs) _
  Handles DataGridView1.CellClick

    If DataGridView1.Columns(e.ColumnIndex).Name = _
      "Details" Then
        MessageBox.Show("You picked " & _
          DataGridView1.Rows(e.RowIndex). _
          Cells("CustomerID").Value)
    End If
End Sub

In einem realistischeren Szenario könnten Sie an diesem Punkt ein neues Fenster erstellen und anzeigen lassen und die Informationen des ausgewählten Datensatzes in das neue Fenster übertragen, um die vollständigen Informationen abzufragen und anzuzeigen.

Bildspalten

Ein weiterer in DataGridView verfügbarer Spaltentyp ist DataGridViewImageColumn. Damit wird innerhalb der Zellgrenzen ein Bild angezeigt. Mit der DataGridViewImageColumn.Layout-Eigenschaft können Sie festlegen, wie das Bild in der Zelle dargestellt wird, ob es gedehnt wird, damit es die Zelle ausfüllt, oder ob es beschnitten wird, wenn es zu breit ist.

Sie können DataGridViewImageColumn auf zwei Arten verwenden. Sie können es erstens ebenso wie DataGridViewButtonColumn manuell erstellen und hinzufügen. Dies ist sinnvoll, wenn Sie Bilddaten anzeigen möchten, die im DataSet selbst nicht enthalten sind. Sie könnten z. B. einen Dateinamen (etwa ProductPic002.gif) abrufen, die entsprechende Datei von einem Netzlaufwerk lesen und sie anschließend im Raster anzeigen. Dazu müssen Sie auf ein ProductPic002.gif-Ereignis wie ProductPic002.gif reagieren. An diesem Punkt wird das Bild für die entsprechende Zeile gelesen, die Bilddaten werden abgerufen und mithilfe der ProductPic002.gif-Eigenschaft der Spalte eingefügt.

Noch einfacher wird die Sache, wenn das DataSet binäre Bilddaten enthält, die nicht mehr manuell bearbeitet werden müssen. Ein Beispiel hierfür ist die Tabelle pub_info in der SQL Server-Pubs-Datenbank, die ein Firmenlogo enthält. Wenn Sie eine Bindung mit dieser Tabelle herstellen, müssen Sie keine zusätzlichen Schritte ausführen. Das DataGridView-Steuerelement erkennt automatisch, dass Sie ein Bild verwenden und erstellt das erforderliche DataGridViewImageColumn-Objekt. (Ein Beispiel für dieses Verfahren finden Sie im Download zu diesem Artikel.)

Bearbeiten mit dem "DataGridView"-Steuerelement

Das DataGrid-Steuerelement war bei Benutzereingaben bekanntermaßen unflexibel, und es gab kaum Möglichkeiten, das Überprüfen von Zellen und Melden von Fehlern anzupassen. Das Verhalten des DataGridView-Steuerelements können Sie dagegen steuern und auf eine Reihe unterschiedlicher Ereignisse reagieren, die in allen Phasen der Bearbeitung ausgelöst werden.

In der Standardeinstellung wird der Bearbeitungsmodus von DataGridView-Zellen aktiviert, wenn der Benutzer mit der Maus auf die Zelle doppelklickt oder die Taste F2 drückt. Sie können das DataGridView-Steuerelement auch so konfigurieren, dass der Bearbeitungsmodus für eine Zelle aktiviert wird, sobald der Benutzer die Zelle ansteuert. Dazu müssen Sie die DataGridView.EditCellOnEnter-Eigenschaft auf TRUE setzen. Sie können die Bearbeitung von Zellen auch programmgesteuert starten und stoppen, indem Sie die Methoden BeginEdit(), CancelEdit(), CommitEdit() und EndEdit() des DataGridView verwenden. Wenn der Benutzer eine Zelle bearbeitet, wird in der Zeilenüberschrift ein Stift als Bearbeitungssymbol angezeigt.

Der Benutzer kann die Bearbeitung durch Drücken der ESC-Taste abbrechen. Wenn die EditCellOnEnter-Eigenschaft auf TRUE gesetzt ist, bleibt die Zelle im Bearbeitungsmodus, alle Änderungen werden jedoch verworfen. Um die Änderung zu übertragen, muss der Benutzer lediglich zu einer anderen Zelle navigieren oder den Fokus auf ein anderes Steuerelement übertragen. Wenn die Position der aktuellen Zelle durch den Code verschoben wird, wird auch die Änderung übertragen.

Um die Bearbeitung einer Zelle zu verhindern, können Sie für DataGridViewCell, DataGridViewColumn, DataGridViewRow oder DataGridView die ReadOnly-Eigenschaft setzen (je nach dem, ob Sie Änderungen nur für die betreffende Zelle, für alle Zellen in der betreffenden Spalte, für alle Zellen in der betreffenden Zeile oder für alle Zellen in der Tabelle verhindern möchten). Das DataGridView-Steuerelement stellt auch ein CellBeginEdit-Ereignis zur Verfügung, das Sie behandeln können, um einen versuchten Bearbeitungsschritt abzubrechen.

Problembehandlung

Standardmäßig gibt DataGridViewTextBoxColumn den Benutzern die Möglichkeit, beliebige Zeichen einschließlich solcher einzugeben, die in der aktuellen Zelle eventuell nicht zulässig sind. Ein Benutzer könnte z. B. nichtnumerische Zeichen in ein numerisches Feld eingeben oder einen Wert angeben, der eine im DataSet definierte ForeignKeyConstraint oder UniqueConstraint verletzt. Diese Probleme werden von DataGridView auf verschiedene Weise behandelt:

  • Wenn der bearbeitete Wert nicht in den erforderlichen Datentyp konvertiert werden kann (der Benutzer hat z. B. Text in eine Zahlenspalte eingegeben), kann der Benutzer die Änderung nicht übertragen und nicht zu einer anderen Zeile navigieren. Die Änderung muss stattdessen abgebrochen werden, oder der Wert muss bearbeitet werden.

  • Wenn der bearbeitete Wert eine Einschränkung im DataSet verletzt, wird die Änderung sofort abgebrochen, nachdem der Benutzer sie durch Navigieren zu einer anderen Zeile oder durch Drücken der Eingabetaste übertragen hat.

Diese leicht verständlichen Standardverhaltensweisen eignen sich gut für die meisten Szenarios. Gegebenenfalls können Sie jedoch auch in die Problembehandlung eingreifen, indem Sie auf das DataGridView.DataError-Ereignis reagieren, das ausgelöst wird, wenn das DataGridView-Steuerelement einen Fehler der Datenquelle abfängt.

Überprüfen der Eingabe

Die Überprüfung unterscheidet sich von der Fehlerbehandlung. Bei der Fehlerbehandlung bearbeiten Sie die vom DataSet gemeldeten Probleme. Bei der Überprüfung erfassen Sie Ihre eigenen benutzerdefinierten Fehlerbedingungen, z. B. Daten, die zwar im DataSet zulässig sind, in Ihrer Anwendung jedoch keinen Sinn machen.

Wenn der Benutzer eine Änderung überträgt, indem er zu einer anderen Zelle navigiert, löst das DataGridView-Steuerelement die Ereignisse CellValidating und CellValidated aus. Danach folgen die Ereignisse RowValidating und RowValidated. Sie können auf diese Ereignisse reagieren, überprüfen, ob der vom Benutzer eingegebene Wert richtig ist, und gegebenenfalls erforderliche Schritte zur nachträglichen Bearbeitung ausführen. Wenn der Wert ungültig ist, wird in der Regel folgendermaßen reagiert: Die Änderung und die Zellnavigation werden abgebrochen (indem die Cancel-Eigenschaft des EventArgs-Objekts auf TRUE gesetzt wird), oder Sie legen eine Fehlermeldung fest, mit der der Benutzer gewarnt wird. Die Fehlermeldung wird entweder in einem anderen Steuerelement abgelegt oder mit der ErrorText-Eigenschaft des entsprepchenden DataGridViewRow- und DataGridViewCell-Objekts im DataGrid angezeigt:

  • Wenn DataGridViewCell.ErrorText gesetzt ist, wird in der Zelle ein Ausrufezeichen angezeigt. Bewegt der Benutzer die Maus über dieses Symbol, wird die Fehlermeldung angezeigt.

  • Wenn DataGridViewRow.ErrorText gesetzt ist, wird in der Zeilenüberschrift am linken Ende der Zeile ein Ausrufezeichen angezeigt. Bewegt der Benutzer die Maus über dieses Symbol, wird die Fehlermeldung angezeigt.

Normalerweise verwenden Sie diese beiden Eigenschaften gleichzeitig und legen sowohl in der Zeile als auch in der Zelle eine Fehlermeldung fest. Im folgenden Beispiel wird geprüft, ob das Feld CompanyName Texteinträge enthält, die zu lang sind. Wird ein fehlerhafter Wert gefunden, wird zu der Zelle ein Fehlersymbol (ein rotes Ausrufezeichen) sowie ein QuickInfo-Text hinzugefügt, der das Problem erläutert.

Private Sub DataGridView1_CellValidating( _
  ByVal sender As System.Object, _
  ByVal e As System.Windows.Forms. _
  DataGridViewCellValidatingEventArgs) _
  Handles DataGridView1.CellValidating

    If DataGridView1.Columns(e.ColumnIndex).Name = _
      "CompanyName" Then
        If CType(e.FormattedValue, String).Length > _
          50 Then
            DataGridView1.Rows( _
              e.RowIndex).Cells(e.ColumnIndex). _
              ErrorText = _
              "The company name is too long."
        End If
    End If
End Sub

Einschränken von Auswahlmöglichkeiten mit einer Listenspalte

Durch die Überprüfung können Sie beliebige Fehlerbedingungen erfassen. Diese Vorgehensweise ist jedoch nicht unbedingt optimal, da der Benutzer ungültige Werte eingeben kann und erst nachträglich versucht wird, diese zu korrigieren. Besser wäre es, den Benutzer von vornherein daran zu hindern, ungültige Werte einzugeben.

Ein Beispiel hierfür ist die Einschränkung einer Spalte auf eine Liste vordefinierter Werte. In diesem Fall muss der Benutzer lediglich den richtigen Wert in einer Liste auswählen und kann ihn nicht manuell eingeben. Interessant ist aber vor allem, dass Sie dies ohne weiteres mithilfe des DataGridViewComboBoxColumn-Objekts implementieren können.

Die Elemente für das DataGridViewComboBoxColumn-Objekt können Sie ähnlich wie bei einem ListBox-Objekt manuell mithilfe der Items-Auflistung hinzufügen. Es ist aber auch möglich, das DataGridViewComboBoxColumn-Objekt an eine andere Datenquelle zu binden. In diesem Fall legen Sie die Datenquelle mithilfe der DataSource-Eigenschaft fest. Mit der DisplayMember-Eigenschaft geben Sie an, welcher Wert in der Spalte angezeigt werden soll, und mit der ValueMember-Eigenschaft bestimmen Sie, welcher Wert für den zugrunde liegenden Spaltenwert verwendet werden soll.

Eine Demonstration bietet das folgende Beispiel, das für die Tabelle Products vorgesehen ist. Jeder Datensatz in dieser Tabelle ist über das Feld CategoryID mit einem Datensatz in der Tabelle Categories verknüpft. Um die Kategorie eines Produkts zu ändern, muss der Benutzer die richtige ID kennen und in das Feld CategoryID eingeben. Besser wäre es, ein DataGridViewComboBoxColumn-Objekt zu verwenden, das an die Tabelle Categories gebunden ist. Für diese Spalte würde CategoryName als Anzeigemember verwendet, während CategoryID der real zugrunde liegende Wert wäre. Die Spalte wäre über die DataPropertyName-Eigenschaft weiterhin an die Tabelle Products gebunden. Das heißt, wenn der Benutzer in der Liste eine neue Kategorie auswählt, wird das Feld CategoryID des Produktdatensatzes automatisch geändert.

Diese Tabelle wird mit dem folgenden Code konfiguriert:

' Remove the auto-generated CategoryID column.
DataGridView1.Columns.Remove("CategoryID")

' Create a list column for the CategoryID.
Dim List As New DataGridViewComboBoxColumn()
List.DisplayIndex = 0
List.HeaderText = "Category"

' This column is bound to the 
' Products.CategoryID field.
List.DataPropertyName = "CategoryID"

' The list is filled from the Categories table.
List.DataSource = ds.Tables("Categories")
List.DisplayMember = "CategoryName"
List.ValueMember = "CategoryID"

' Add the column.
DataGridView1.Columns.Add(List)

Schlussbemerkung

Dieser Artikel gibt einen Überblick über das DataGridView-Steuerelement, eines der am meisten erwarteten neuen Steuerelemente von .NET. Im Unterschied zum DataGrid eignet sich DataGridView gut für verschiedene realistische Szenarios, beispielsweise für Szenarios mit Datenbindung und Bearbeitung durch Benutzer, sowie für Szenarios, in denen lediglich statischer Text angezeigt wird. Insgesamt kommen Sie damit einer umfassenden Datenlösung mit dem .NET-Framework am nächsten. Zudem ist dieses Steuerelement einer der überzeugendsten Gründe für Windows Forms-Entwickler, auf .NET 2.0 zu aktualisieren.

501MACDONALD.ZIP downloaden

Weitere Informationen zu Visual Studio .NET Developer und Pinnacle Publishing finden Sie auf der Website http://www.pinpub.com/ (in englischer Sprache).

Hinweis: Diese Website wird nicht von der Microsoft Corporation betrieben. Microsoft ist nicht für deren Inhalte verantwortlich.

Dieser Artikel ist bereits in der Visual Studio .NET-Developer-Ausgabe vom Januar 2005 erschienen. Copyright 2005, Pinnacle Publishing, Inc., sofern nicht anders angegeben. Alle Rechte vorbehalten. Visual Studio .NET Developer ist eine unabhängige Publikation von Pinnacle Publishing, Inc. Der Artikel oder Teile des Artikels dürfen nicht ohne vorherige Zustimmung von Pinnacle Publishing reproduziert werden (ausgenommen kurze Zitate in Artikeln und Rezensionen). Sie erreichen Pinnacle Publishing, Inc. unter der Telefonnummer 1-800-788-1900.


Anzeigen: