Galileo Computing < openbook >
Galileo Computing - Programming the Net
Galileo Computing - Programming the Net


Einstieg in ASP.NET von Matthias Lohrer
Einstieg in ASP.NET
gp Kapitel 12 ASP.NET und Datenbanken
  gp 12.1 Auf Datenbanken zugreifen – ein Crashkurs
    gp 12.1.1 Eine Tabelle im Browser anzeigen
    gp 12.1.2 Über den Browser einen Datensatz hinzufügen
  gp 12.2 Wie ADO.NET funktioniert – ein Überblick
  gp 12.3 Die Verbindung zur Datenbank herstellen
    gp 12.3.1 OleDbConnection
    gp 12.3.2 SqlConnection
  gp 12.4 Daten lesen mit SqlCommand und OleDbCommand
    gp 12.4.1 ExecuteReader
    gp 12.4.2 ExecuteNonQuery und die Parameters-Collection
    gp 12.4.3 ExecuteScalar
  gp 12.5 SqlDataReader und OleDbDataReader
    gp 12.5.1 Ein Reader-Objekt an ein Steuerelement binden
    gp 12.5.2 Ein Reader-Objekt an ein Listensteuerelement binden
    gp 12.5.3 Ein Reader-Objekt zeilenweise auswerten
  gp 12.6 Die DataSet-Klasse
    gp 12.6.1 Das Zusammenspiel von Command, Adapter und DataSet
    gp 12.6.2 Mehrere Tabellen in ein DataSet-Objekt einlesen
    gp 12.6.3 Auf einzelne Zeilen, Spalten und Tabellen eines DataSet-Objekts gezielt zugreifen
    gp 12.6.4 Relationen zwischen Tabellen festlegen
  gp 12.7 DataViews verwenden
    gp 12.7.1 Tabellen sortieren
    gp 12.7.2 Tabellen nach Inhalten filtern
    gp 12.7.3 Nach dem Zeilenstatus filtern
    gp 12.7.4 In Tabellen suchen
  gp 12.8 Mit ASP.NET Daten bearbeiten
  gp 12.9 Daten bearbeiten mit dem Command-Objekt
  gp 12.10 In-Place-Editing mit dem DataGrid-Steuerelement
    gp 12.10.1 Die EditItemIndex-Eigenschaft
    gp 12.10.2 Das asp:DataGrid-Tag anpassen
    gp 12.10.3 OnEditCommand: Daten bearbeiten
    gp 12.10.4 OnCancelCommand: Die Bearbeitung abbrechen
    gp 12.10.5 OnUpdateCommand: Die Änderungen sichern
    gp 12.10.6 Das Repeater-Steuerelement verwenden
    gp 12.10.7 Die Ereignisse des Repeater-Steuerelements auswerten
  gp 12.11 Das DataList-Steuerelement
    gp 12.11.1 In-Place-Editing mit dem DataList-Steuerelement


Galileo Computing

12.10 In-Place-Editing mit dem DataGrid-Steuerelement  downtop

Das DataGrid-Steuerelement bietet die Möglichkeit, Daten im In-Place-Editing-Modus zu bearbeiten. Für die Realisierung dieses anwenderfreundlichen Verfahrens müssen mehrere ASP.NET-Zahnräder korrekt ineinander greifen. Die folgenden Erläuterungen stellen die benötigten Bestandteile nacheinander einzeln vor. Am Anfang steht Code, der nur einen Teil der benötigten Funktionalität umsetzt. Schritt für Schritt kommen weitere Elemente dazu, bis am Schluss der gesamte Bearbeitungszyklus funktioniert.


Galileo Computing

12.10.1 Die EditItemIndex-Eigenschaft  downtop

Wenn Sie die voreingestellten Standardeigenschaften des DataGrid-Steuerelements verwenden und das Steuerelement an eine Tabelle als Datenquelle binden, dann ist das Ergebnis im Browser eine ganz einfache Tabelle ohne Besonderheiten. Das DataGrid-Steuerelement bietet einige Schalter, mit denen Sie die Darstellung und auch die Funktionalität dieser Tabelle erweitern können. Für die Bearbeitung von Daten kommt der Eigenschaft EditItemIndex eine zentrale Bedeutung zu. Der Eigenschaft EditItemIndex übergeben Sie die Ordnungszahl des Datensatzes, den Sie bearbeiten möchten. Wenn Sie anschließend das DataGrid-Steuerelement mit Daten füllen, hat die neu erstellte Tabelle eine Besonderheit: Die Felder des Datensatzes, den Sie in EditItemIndex angegeben haben, werden jetzt mit Hilfe von Eingabefeldern dargestellt. Der Anwender kann den Inhalt dieses Datensatzes bearbeiten. Damit ergibt sich folgende charakteristische Codesequenz:

   ' Der vierte Datensatz soll bearbeitet werden.
   ' Zur Basis Null ergibt sich eine 3 
   myGrid.EditItemIndex = 3
   ' ... 
   ' Datenbankverbindung aufbauen
   ' ...
   sql = "SELECT * FROM Versandfirmen"
   Dim cmd As New OleDbCommand(sql, conn)
   ' Das DataGrid-Steuerelement mit Daten füllen
   myGrid.DataSource = cmd.ExecuteReader()   
   ' Wegen der gesetzten EditItemIndex-Eigenschaft
   ' wird eine Zeile im Bearbeitungsmodus angezeigt
   DataBind()

Der Code legt zunächst fest, welcher Datensatz bearbeitet werden soll, indem er die Eigenschaft EditItemIndex entsprechend setzt. Anschließend wird durch den Aufruf von ExecuteReader() wie gewohnt die Datenquelle des DataGrid-Steuerelements gefüllt. Die betroffene Zeile kann nun bearbeitet werden. Wenn der Editiervorgang abgeschlossen ist und die Tabelle wieder in der normalen Form angezeigt werden soll, setzen Sie die Eigenschaft EditItemIndex auf -1. Das ist das Signal für das DataGrid-Steuerelement, dass keine Zeile bearbeitet werden soll. Wenn Sie damit erneut ExecuteReader() aufrufen, erscheint wieder die normale Tabelle ohne Besonderheiten.

db_17.aspx realisiert diesen ersten Schritt im Zusammenhang. Abbildung 12.18 zeigt die Darstellung im Browser. Die dritte Zeile kann bearbeitet werden, aber bislang gibt es noch keine Möglichkeit, die Änderungen zu speichern oder einen anderen Datensatz zu bearbeiten. Der Code muss also noch entsprechend erweitert werden. Abgesehen von der Verwendung der Eigenschaft EditItemIndex wird in db_17.aspx auch die Deklaration des asp:DataGrid-Tags im HTML-Teil der aspx-Seite angepasst. Diese Änderungen werden im nächsten Abschnitt erläutert.

<!-- db_17.aspx --> 
<%@ Page Language="VB" Debug="True" Strict="True" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.OleDb" %>
<script runat="server">
Sub Page_Load (ByVal Sender As Object, _
               ByVal E As EventArgs)
   ' Verbindungszeichenfolge zusammensetzen
   Dim connStr As String 
   connStr = "Provider=Microsoft.Jet.OLEDB.4.0;"
   connStr += _
  "Data Source=E:\ASPdotNETBuch\Listings\Nordwind.mdb;"
   ' Verbindung zur Datenbank herstellen
   Dim conn As New OleDbConnection(connStr)
   conn.Open()
   
   ' Der dritte Datensatz soll bearbeitet werden
   myGrid.EditItemIndex = 2
   
   ' Die Tabelle Versandfirmen anzeigen
   Dim sql As String
   sql = "SELECT * FROM Versandfirmen"
   Dim cmd As New OleDbCommand(sql, conn)
   myGrid.DataSource = cmd.ExecuteReader()   
   DataBind()
   conn.Close()
End Sub
</script>
<html><head><title>In-Place-Editing mit dem 
DataGrid-Steuerelement, Schritt 1</title></head>
<body>
<h3>In-Place-Editing mit dem 
DataGrid-Steuerelement<br>Schritt 1</h3>
<form runat="server" >
<asp:DataGrid id="myGrid" runat="server"
              AutoGenerateColumns="false" >
<Columns>
   <asp:BoundColumn
        DataField="Firma"
        HeaderText="Firma" />
   <asp:BoundColumn
        DataField="Telefon"
        HeaderText="Telefon" />
</Columns>
</asp:DataGrid>
</form></body></html>

Galileo Computing

12.10.2 Das asp:DataGrid-Tag anpassen  downtop

Wenn Sie das DataGrid-Steuerelement in der einfachsten Form verwenden, gibt das Steuerelement die zugrunde liegenden Daten in der Standardform aus.

<asp:DataGrid id="myGrid" runat="server" />

Diese Standardausgabeform enthält alle Spalten und Zeilen und keine Daten sind in irgendeiner Form hervorgehoben. Wenn Sie nicht alle Spalten ausgeben möchten oder zusätzliche Spalten ausgeben wollen oder wenn Sie einzelne Spalten in irgendeiner Form hervorheben möchten, dann realisieren Sie diese individuelle Gestaltung in zwei Schritten:

Abbildung
Hier klicken, um das Bild zu Vergrößern

Abbildung 12.18 Die EditItemIndex-Eigenschaft des DataGrid-Steuerelements enthält die Ordnungszahl der zu bearbeitenden Zeile.

1. Sie verwenden das Attribut AutoGenerateColumns="false" im asp:DataGrid-Steuerelement. 2. Sie fügen innerhalb des asp:DataGrid-Elements ein Element Columns hinzu, in dem Sie die gewünschten Spalten beschreiben.

In db_17.aspx sieht das Ergebnis so aus:

<asp:DataGrid id="myGrid" runat="server"
              AutoGenerateColumns="false" >
<Columns>
   <asp:BoundColumn
        DataField="Firma"
        HeaderText="Firma" />
   <asp:BoundColumn
        DataField="Telefon"
        HeaderText="Telefon" />
</Columns>
</asp:DataGrid>

Das ist noch wenig spektakulär. Das Ergebnis unterscheidet sich von der Standardausgabe zunächst nur darin, dass das Feld Firmen-Nr nicht mit aufgeführt wird.

Innerhalb des Columns-Elements definieren Sie mit Hilfe weiterer Elemente die Merkmale der einzelnen Spalten. ASP.NET stellt fünf vordefinierte Spaltentypen zur Verfügung, die sich jeweils individuell anpassen lassen:

gp  BoundColumn ist der Standardspaltentyp. Die Spalte ist an die Inhalte einer Spalte der Datenquelle gebunden.
gp  HyperLinkColumn, ButtonColumn und TemplateColumn bieten weiter gehende Möglichkeiten, die hier zunächst noch nicht interessieren sollen.
gp  Eine Spalte vom Typ EditCommandColumn benötigen wir, um für jede Zeile die Bearbeitungsbefehle angeben zu können.

Das Beispiel verwendet zunächst nur den Spaltentyp BoundColumn. Im Attribut DataField geben Sie den Namen der gewünschten Spalte an. Im Attribut HeaderText legen Sie den Text für den Spaltenkopf fest.

Als nächsten Schritt ergänzen Sie eine Spalte vom Typ EditCommandColumn hinter den beiden Datenspalten. Das Columns-Element bekommt damit diese Form:

<Columns>
   <asp:BoundColumn
        DataField="Firma"
        HeaderText="Firma" />
   <asp:BoundColumn
        DataField="Telefon"
        HeaderText="Telefon" />
   <asp:EditCommandColumn
        EditText="Bearbeiten"
        CancelText="Abbrechen"
        UpdateText="Speichern"
        HeaderText="Bearbeitung" /> 
</Columns>

Weitere Änderungen müssen Sie an db_17.aspx nicht vornehmen. db_18.aspx enthält diese erweiterte Form. Bei einem Blick auf die Darstellung im Browser (siehe Abbildung 12.19) wird deutlich, wie das asp:EditCommandColumn-Element arbeitet.

Zeilen, die nicht bearbeitet werden, erhalten in der Spalte Bearbeitung einen Link Bearbeiten. Die Zeile, die momentan bearbeitet wird, erhält in dieser Spalte zwei Links: Speichern und Abbrechen. Diese Bezeichnungen haben Sie mit den Attributen EditText="Bearbeiten", CancelText="Abbrechen", UpdateText="Speichern" und HeaderText="Bearbeitung" im asp:EditCommandColumn-Element festgelegt.

Abbildung
Hier klicken, um das Bild zu Vergrößern

Abbildung 12.19 Der Spaltentyp EditCommandColumn stellt die typischen Bearbeitungsfunktionen zur Verfügung.

Wenn Sie die Links anklicken, passiert noch nichts. Die Funktionalität für diese Links müssen Sie erst noch erstellen. Sie weisen den Links eine Funktion zu, indem Sie für jede Funktion eine entsprechende Prozedur erstellen und im asp:DataGrid-Element die Attribute OnEditCommand, OnCancelCommand und OnUpdateCommand definieren. Wenn Ihre Ereignisprozeduren myGridEdit, myGridCancel und myGridUpdate heißen, erhält das Start-Tag von asp:DataGrid diese Form:

<asp:DataGrid id="myGrid" runat="server"
              AutoGenerateColumns="false"
              OnEditCommand="myGridEdit"
              OnCancelCommand="myGridCancel"
              OnUpdateCommand="myGridUpdate" >

In den folgenden Abschnitten werden diese zu erstellenden Ereignisprozeduren erläutert.


Galileo Computing

12.10.3 OnEditCommand: Daten bearbeiten  downtop

Was soll passieren, wenn ein Anwender in der Spalte Bearbeitung den Link Bearbeiten anklickt? Der Anwender erwartet, dass anschließend die Inhalte der Spalten in Textfeldern angezeigt werden, die er bearbeiten kann. Außerdem soll die Spalte Bearbeitung die Einträge Speichern und Abbrechen bekommen.

Wie lassen sich diese Anforderungen umsetzen? Zwei Schritte reichen aus:

1. Setzen Sie die EditItemIndex-Eigenschaft des DataGrid-Steuerelements auf die Nummer des zu bearbeitenden Datensatzes. 2. Veranlassen Sie, dass die Tabelle neu gezeichnet wird.

Das DataGrid-Steuerelement wird dann beim Neuzeichnen sämtliche Änderungen in der Darstellung selbstständig vornehmen.

Der Schritt 2 wird auch bei den anderen Ereignisprozeduren für das Sichern und das Abbrechen immer wieder benötigt. Also lagern Sie diesen Vorgang in eine separate Prozedur aus, die Sie an mehreren Stellen aufrufen können. Im Beispiel bekommt diese Prozedur den Namen anzeigeAktualisieren(). Für die Ereignisprozedur myGridEdit bleiben damit nur noch zwei Zeilen Code übrig:

Public Sub myGridEdit _
              (ByVal Sender As Object, _
               ByVal E As DataGridCommandEventArgs)
   myGrid.EditItemIndex = E.Item.ItemIndex
   anzeigeAktualisieren()
End Sub

Die entscheidende Frage für diese Prozedur lautet, wie sie ermitteln kann, in welcher Zeile der Anwender Bearbeiten angeklickt hat. Diese Information ist über das DataGridCommandEventArgs-Objekt E zugänglich. Über die Eigenschaft Item des DataGridCommandEventArgs-Objekts erreichen Sie das Element mit der Befehlsquelle in Form eines DataGridItem-Objekts. Dessen Indexposition ermitteln Sie über die ItemIndex-Eigenschaft. Indem Sie diesen Wert der Eigenschaft myGrid.EditItemIndex zuweisen, ist auch schon alles für die Anzeige der Tabelle mit Bearbeitungsfunktion vorbereitet.

Die Prozedur anzeigeAktualisieren enthält den bereits bekannten Code, der bislang innerhalb von Page_Load() ablief. Wenn Sie den Code hier herausnehmen, müssen Sie sich noch etwas für den Fall überlegen, dass das Skript erstmalig aufgerufen wird. In diesem Fall soll die Tabelle ganz normal angezeigt werden, womit für Page_Load diese drei Zeilen übrig bleiben:

   If Not IsPostBack() Then
      anzeigeAktualisieren()
   End If

Da Sie im asp:DataGrid-Steuerelement auch bereits die Attribute OnCancelCommand="myGridCancel" und OnUpdateCommand="myGridUpdate" gesetzt haben, fügen Sie hierfür jeweils noch leere Prozeduren hinzu, damit beim Kompilieren keine Fehlermeldung ausgegeben wird. db_19.aspx fasst die Änderungen zusammen, die Sie bis zu diesem Punkt am Code vorgenommen haben.

<!-- db_19.aspx --> 
<%@ Page Language="VB" Debug="True" Strict="True" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.OleDb" %>
<script runat="server">
Public Sub anzeigeAktualisieren()
   ' Verbindungszeichenfolge zusammensetzen
   Dim connStr As String 
   connStr = "Provider=Microsoft.Jet.OLEDB.4.0;"
   connStr += _
  "Data Source=E:\ASPdotNETBuch\Listings\Nordwind.mdb;"
   ' Verbindung zur Datenbank herstellen
   Dim conn As New OleDbConnection(connStr)
   conn.Open()
   ' Die Tabelle Versandfirmen anzeigen
   Dim sql As String
   sql = "SELECT * FROM Versandfirmen"
   Dim cmd As New OleDbCommand(sql, conn)
   myGrid.DataSource = cmd.ExecuteReader()   
   DataBind()
   conn.Close()
End Sub

Sub Page_Load (ByVal Sender As Object, _
               ByVal E As EventArgs)
   If Not IsPostBack() Then
      anzeigeAktualisieren()
   End If               
End Sub

Public Sub myGridEdit _
              (ByVal Sender As Object, _
               ByVal E As DataGridCommandEventArgs)
   myGrid.EditItemIndex = E.Item.ItemIndex
   anzeigeAktualisieren()
End Sub

Public Sub myGridCancel _
              (ByVal Sender As Object, _
               ByVal E As DataGridCommandEventArgs)
End Sub

Public Sub myGridUpdate _
              (ByVal Sender As Object, _
               ByVal E As DataGridCommandEventArgs)
End Sub
</script>
<html><head><title>In-Place-Editing mit dem 
DataGrid-Steuerelement, Schritt 3: Das
EditCommand-Ereignis behandeln</title></head>
<body>
<h3>In-Place-Editing mit dem DataGrid-Steuerelement<br>
Schritt 3: Das EditCommand-Ereignis behandeln
</h3>
<form runat="server" >
<asp:DataGrid id="myGrid" runat="server"
              AutoGenerateColumns="false"
              OnEditCommand="myGridEdit"
              OnCancelCommand="myGridCancel"
              OnUpdateCommand="myGridUpdate" >
<Columns>
   <asp:BoundColumn
        DataField="Firma"
        HeaderText="Firma" />
   <asp:BoundColumn
        DataField="Telefon"
        HeaderText="Telefon" />
   <asp:EditCommandColumn
        EditText="Bearbeiten"
        CancelText="Abbrechen"
        UpdateText="Speichern"
        HeaderText="Bearbeitung" /> 
</Columns>
</asp:DataGrid>
</form></body></html>

Die Änderungen, die Sie bis hierhin durchgeführt haben, bewirken, dass Sie hinter jeder Zeile Bearbeiten anklicken können und dass anschließend diese Zeile in den Bearbeitungsmodus wechselt. Als Nächstes sind die Funktionen für das Abbrechen und für das Speichern der Änderungen zu erstellen.


Galileo Computing

12.10.4 OnCancelCommand: Die Bearbeitung abbrechen  downtop

Die Prozedur für das Abbrechen des Editiervorgangs ist denkbar einfach. So, wie Sie bei myGridEdit die Zeile angeben, die bearbeitet werden soll, geben Sie bei myGridCancel an, dass keine Zeile bearbeitet werden soll. Dafür setzen Sie die Eigenschaft myGrid.EditItemIndex auf -1 und so kommt auch myGridCancel mit zwei Zeilen Code aus:

Public Sub myGridCancel _
              (ByVal Sender As Object, _
               ByVal E As DataGridCommandEventArgs)
   myGrid.EditItemIndex = -1
   anzeigeAktualisieren()
End Sub

Galileo Computing

12.10.5 OnUpdateCommand: Die Änderungen sichern  downtop

Im Vergleich zu den beiden anderen Ereignisprozeduren hat myGridUpdate richtig viel zu tun. Hier zunächst der Code, im Anschluss daran die Erläuterungen.

Public Sub myGridUpdate _
              (ByVal Sender As Object, _
               ByVal E As DataGridCommandEventArgs)
   Dim connStr As String 
   connStr = "Provider=Microsoft.Jet.OLEDB.4.0;"
   connStr += _
  "Data Source=E:\ASPdotNETBuch\Listings\Nordwind.mdb;"
   Dim conn As New OleDbConnection(connStr)
   conn.Open()
   Dim sqlUpdate As String
   sqlUpdate = "UPDATE Versandfirmen SET Firma='"
   sqlUpdate &= _
      CType(E.Item.Cells(0).Controls(0), TextBox).Text 
   sqlUpdate &= "', Telefon ='"
   sqlUpdate &= _
      CType(E.Item.Cells(1).Controls(0), TextBox).Text
   sqlUpdate &= "' WHERE [Firmen-Nr] = "
   sqlUpdate &= CStr(myGrid.DataKeys(E.Item.ItemIndex))
   Dim cmd As New OleDbCommand()
   cmd.Connection = conn
   cmd.CommandText = sqlUpdate
   cmd.ExecuteNonQuery()
   conn.Close()
   myGrid.EditItemIndex = -1
   anzeigeAktualisieren()   
End Sub

Der größte Teil des Codes ist bereits bekannt. Die Prozedur baut die Datenbankverbindung auf, setzt einen SQL-Befehl für ein Datenbank-Update zusammen und führt ihn mit Hilfe eines OleDbCommand-Objekts aus. Im Anschluss wird myGrid.EditItemIndex auf -1 gesetzt und die Tabellendarstellung aktualisiert, so dass keine Zeile mehr bearbeitet wird.

Es stellen sich zwei neue Aufgaben:

1. Sie müssen die Eingaben des Anwenders ermitteln. 2. Zur eindeutigen Identifizierung des Datensatzes benötigen Sie die Angabe der Firmen-Nr. Die Tabelle selbst enthält die Firmen-Nr. aber nicht.

Die Eingaben des Anwenders ermitteln

Der vom Anwender editierte Firmenname versteckt sich hinter diesem Ausdrucksungetüm:

CType(E.Item.Cells(0).Controls(0), TextBox).Text

Dieser Ausdruck verwendet zweimal die Default-Eigenschaft Item. Wenn man diese Default-Eigenschaft zusätzlich ausdrücklich hinschreibt, ergibt sich diese Form:

CType(E.Item.Cells.Item(0).Controls.Item(0), TextBox).Text

Dieser Ausdruck soll Schritt für Schritt aufgelöst werden.

gp  E E
Der Ereignisprozedur myGridUpdate wurde in der Variablen E ein Objekt vom Typ DataGridCommandEventArgs übergeben.
gp  E E.Item
Die Eigenschaft Item von E gibt ein Objekt vom Typ DataGridItem zurück. Ein DataGridItem repräsentiert eine Zeile eines DataGrid-Objekts.
gp  E E.Item.Cells
Die Eigenschaft Cells dieses DataGridItem-Objekts führt zu der von TableRow geerbten Cells-Eigenschaft, die ihrerseits ein Objekt vom Typ TableCellCollection enthält.
gp  E E.Item.Cells.Item(0) oder verkürzt E.Item.Cells(0)
Über die Default-Eigenschaft Item(nummer) erreichen Sie das einzelne TableCell-Objekt. Die erste Zelle enthält den Firmennamen.
gp  E E.Item.Cells(0).Controls
Die einzelne Zelle enthält mehrere Controls. Die Klasse TableCell kennt die Eigenschaft Controls, die ein Objekt vom Typ ControlCollection enthält.
gp  E E.Item.Cells(0).Controls.Item(0) oder verkürzt
E.Item.Cells(0).Controls(0)
Über die Default-Eigenschaft Item (nummer) der ControlCollection erreichen wir das einzelne Control-Objekt. Das erste Control-Objekt ist das Texteingabefeld: Controls(0).
gp  E CType(E.Item.Cells(0).Controls(0), TextBox)
Ein Control-Objekt hat etwas nicht: Es hat keine Value- oder Text-Eigenschaft, mit der sich der Inhalt des Eingabefeldes unmittelbar auslesen ließe. Sie müssen das Control-Objekt erst wieder zu dem machen, was es eigentlich ist, nämlich ein Objekt vom Typ TextBox. Dazu verwenden Sie die Konvertierungsfunktion CType.
gp  E CType(E.Item.Cells(0).Controls(0), TextBox).Text
Das TextBox-Objekt hat schließlich eine Eigenschaft Text, die den vom Anwender editierten Text enthält.

Damit haben Sie erfolgreich den geänderten Firmennamen ermittelt. Um die geänderte Telefonnummer zu ermitteln, reicht es aus, mit E.Item.Cells(1) die zweite Zelle zu adressieren. Der Rest des Ausdrucks bleibt gleich.

Den Wert des Schlüsselfeldes ermitteln

Für den SQL-Befehl, der das Datenbank-Update ausführen soll, benötigen Sie auf jeden Fall den Wert des Schlüsselfeldes. Er muss in der Klausel WHERE [Firmen-Nr] = xyz an der Stelle von xyz eingesetzt werden. Die Tabelle selbst enthält die Spalte Firmen-Nr jedoch nicht. Wie also können Sie diesen Wert ermitteln?


Tipp   So geht's: Bei der Deklaration des asp:DataGrid-Steuerelements fügen Sie das Attribut DataKeyField="Firmen-Nr" hinzu. Damit teilen Sie dem DataGrid-Steuerelement mit, dass diese Spalte die Schlüssel enthält.

Im Code der Prozedur myGridUpdate ermitteln Sie den zugehörigen Schlüssel-Wert mit diesem Ausdruck:

CStr(myGrid.DataKeys(E.Item.ItemIndex))

Die DataKeys-Eigenschaft des DataGrid-Objekts ruft ein Objekt vom Typ DataKeyCollection ab. Diese Auflistung enthält die Schlüsselwerte aller Datensätze. Von der Deklaration DataKeyField="Firmen-Nr" weiß das Steuerelement, dass es hier die Spalte Firmen-Nr verwenden soll. Auf den einzelnen Wert greifen Sie über die Default-Eigenschaft Item zu. Den Schlüsselwert des dritten Datensatzes würden Sie also über myGrid.DataKeys.Item(2) beziehungsweise myGrid.DataKeys(2) ansprechen. Es bleibt die Aufgabe, die Nummer des bearbeiteten Datensatzes zu ermitteln. Das Verfahren kennen Sie bereits aus den beiden anderen Ereignisprozeduren: E.Item.Itemindex liefert den gesuchten Wert. myGrid.DataKeys(E.Item.ItemIndex) gibt ein Objekt vom Typ Object zurück. Mit CStr wandeln Sie das Objekt in einen String um. Damit haben Sie den Schlüsselwert ermittelt und können ihn in den SQL-Befehl einbauen.

Damit ist der komplette Bearbeitungszyklus umgesetzt. db_20.aspx zeigt den kompletten Code im Zusammenhang.

<!-- db_20.aspx --> 
<%@ Page Language="VB" Debug="True" Strict="True" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.OleDb" %>
<script runat="server">
Public Sub anzeigeAktualisieren()
   ' Verbindungszeichenfolge zusammensetzen
   Dim connStr As String 
   connStr = "Provider=Microsoft.Jet.OLEDB.4.0;"
   connStr += _
  "Data Source=E:\ASPdotNETBuch\Listings\Nordwind.mdb;"
   ' Verbindung zur Datenbank herstellen
   Dim conn As New OleDbConnection(connStr)
   conn.Open()
   ' Die Tabelle Versandfirmen anzeigen
   Dim sql As String
   sql = "SELECT * FROM Versandfirmen"
   Dim cmd As New OleDbCommand(sql, conn)
   myGrid.DataSource = cmd.ExecuteReader()   
   DataBind()
   conn.Close()
End Sub

Sub Page_Load (ByVal Sender As Object, _
               ByVal E As EventArgs)
   If Not IsPostBack() Then
      anzeigeAktualisieren()
   End If               
End Sub

Public Sub myGridEdit _
              (ByVal Sender As Object, _
               ByVal E As DataGridCommandEventArgs)
   myGrid.EditItemIndex = E.Item.ItemIndex
   anzeigeAktualisieren()
End Sub

Public Sub myGridCancel _
              (ByVal Sender As Object, _
               ByVal E As DataGridCommandEventArgs)
   myGrid.EditItemIndex = -1
   anzeigeAktualisieren()
End Sub

Public Sub myGridUpdate _
              (ByVal Sender As Object, _
               ByVal E As DataGridCommandEventArgs)
   ' Verbindungszeichenfolge zusammensetzen
   Dim connStr As String 
   connStr = "Provider=Microsoft.Jet.OLEDB.4.0;"
   connStr += _
  "Data Source=E:\ASPdotNETBuch\Listings\Nordwind.mdb;"
   Dim conn As New OleDbConnection(connStr)
   conn.Open()
   Dim sqlUpdate As String
   sqlUpdate = "UPDATE Versandfirmen SET Firma='"
   sqlUpdate &= _
      CType(E.Item.Cells(0).Controls(0), TextBox).Text 
   sqlUpdate &= "', Telefon ='"
   sqlUpdate &= _
      CType(E.Item.Cells(1).Controls(0), TextBox).Text
   sqlUpdate &= "' WHERE [Firmen-Nr] = "
   sqlUpdate &= CStr(myGrid.DataKeys(E.Item.ItemIndex))
   Dim cmd As New OleDbCommand()
   cmd.Connection = conn
   cmd.CommandText = sqlUpdate
   cmd.ExecuteNonQuery()
   conn.Close()
   myGrid.EditItemIndex = -1
   anzeigeAktualisieren()   
End Sub
</script>
<html><head><title>In-Place-Editing mit dem 
DataGrid-Steuerelement, Schritt 4: Die Ereignisse
UpdateCommand und CancelCommand behandeln</title></head>
<body>
<h3>In-Place-Editing mit dem DataGrid-Steuerelement<br>
Schritt 4: Die Ereignisse UpdateCommand und 
CancelCommand behandeln
</h3>
<form runat="server" >
<asp:DataGrid id="myGrid" runat="server"
              AutoGenerateColumns="false"
              DataKeyField="Firmen-Nr"
              OnEditCommand="myGridEdit"
              OnCancelCommand="myGridCancel"
              OnUpdateCommand="myGridUpdate" >
<Columns>
   <asp:BoundColumn
        DataField="Firma"
        HeaderText="Firma" />
   <asp:BoundColumn
        DataField="Telefon"
        HeaderText="Telefon" />
   <asp:EditCommandColumn
        EditText="Bearbeiten"
        CancelText="Abbrechen"
        UpdateText="Speichern"
        HeaderText="Bearbeitung" /> 
</Columns>
</asp:DataGrid>
</form></body></html>

Galileo Computing

12.10.6 Das Repeater-Steuerelement verwenden  downtop

Das Repeater-Steuerelement kann ebenfalls an eine Datenquelle gebunden werden. Als DataSource kann jedes Objekt angegeben werden, das von System.Collections.IEnumerable abgeleitet ist. Neben Datenbanktabellen gehören dazu etwa auch Arrays oder die Klasse System.Collections.Hashtable.

Das Repeater-Steuerelement gibt die Datensätze seiner Datenquelle in gleichmäßiger Form aus. Für die Gestaltung der Ausgabe kann der Entwickler maximal fünf Vorlagen in Form von HTML-Code erstellen:

gp  HeaderTemplate beschreibt den Anfang der Auflistung. Hier kann beispielsweise ein Tabellenkopf definiert werden.
gp  ItemTemplate legt die Ausgabeform für den einzelnen Datensatz fest.
gp  Den Raum zwischen den einzelnen Datensätzen gestalten Sie mit dem SeparatorTemplate.
gp  Wenn Sie die Daten in tabellarischer Form ausgeben, dann erhöht es die Lesbarkeit, wenn die Zeilen nicht alle gleich aussehen, sondern beispielsweise abwechselnd weiß und grau hinterlegt sind. Für diesen Effekt definieren Sie ein AlternatingItemTemplate, das sich in der Ausgabe stets mit ItemTemplate abwechselt.
gp  Zu guter Letzt schließen Sie die Darstellung mit dem FooterTemplate ab.

Bei der Deklaration eines Repeater-Steuerelements müssen Sie mindestens ein ItemTemplate definieren. Die übrigen Elemente sind optional.

db_21.aspx gibt beispielhaft eine Liste der Versandunternehmen mit Telefonnummern aus, wie in Abbildung 12.20 zu sehen.

<!-- db_21.aspx --> 
<%@ Page Language="VB" Debug="True" Strict="True" 
         EnableViewstate="false" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.OleDb" %>
<script runat="server">
Sub Page_Load (ByVal Sender As Object, _
               ByVal E As EventArgs)
   Dim connStr As String 
   connStr = "Provider=Microsoft.Jet.OLEDB.4.0;"
   connStr += _
  "Data Source=C:\ASPdotNETBuch\Listings\Nordwind.mdb;"
   Dim conn As New OleDbConnection(connStr)
   conn.Open()
   Dim sql As String
   sql = "SELECT * FROM Versandfirmen"
   Dim cmd As New OleDbCommand(sql, conn)
   Dim myDataReader As OleDbDataReader
   myDataReader = cmd.ExecuteReader()
   myRepeat.DataSource = myDataReader
   myRepeat.DataBind()
   myDataReader.Close()
   conn.Close()               
End Sub
</script>
<html><head><title>
Repeater-Steuerelement
</title></head>
<body>
<h3>Repeater-Steuerelement</h3>
<form runat="server">
<asp:repeater id="myRepeat" runat="server" >
   
   <HeaderTemplate>
      Versandfirmen mit Tel-Nr.: <ul>
   </HeaderTemplate>
   
   <ItemTemplate>
      <li><%# DataBinder.Eval _
                      (Container.DataItem, "Firma") %>
      , <%# DataBinder.Eval _
                     (Container.DataItem, "Telefon")%>
   </ItemTemplate>

   <FooterTemplate>
      </ul>
   </FooterTemplate>
         
</asp:repeater>
</form>
</body></html>

Abbildung
Hier klicken, um das Bild zu Vergrößern

Abbildung 12.20 Maximal fünf verschiedene HTML-Vorlagen steuern die Ausgabe des Repeater-Steuerelements.

db_21.aspx deklariert im HTML-Bereich das asp:repeater-Element. Es enthält drei Template-Elemente.

gp  Der HeaderTemplate legt den Beginn fest. Hier wird der Text Versandfirmen mit Tel-Nr.: ausgegeben und die ungeordnete Liste wird mit dem HTML-Tag <ul> eingeleitet.
gp  Das ItemTemplate legt die Ausgabeform für die einzelnen Datensätze fest. Es beginnt jeweils mit einem <li>-Tag. Der folgende Ausdruck sorgt dafür, dass die Firma ausgegeben wird. Es folgt ein Komma und abschließend die Telefonnummer.
gp  Zum Abschluss gibt das FooterTemplate das schließende Tag </ul> aus.

Die beiden anderen Templates verwendet dieses Beispiel nicht. Das SeparatorTemplate und das AlternatingItemTemplate sind vorwiegend bei der Ausgabe von Tabellen interessant.

Die Page_Load-Prozedur enthält keine Neuigkeiten. Das OleDbDataReader-Objekt wird in gewohnter Manier erstellt und an die Eigenschaft myRepeat.DataSource gebunden. Anschließend sorgt myRepeat.DataBind() für die konkrete Ausführung der Datenbindung.

Auf den ersten Blick ungewöhnlich ist die Ausgabe der Daten selbst innerhalb der Templates:

<%# DataBinder.Eval (Container.DataItem, "Firma") %>

Die Klammersyntax <%# ... %> ist eine spezielle Syntax von ASP.NET für Datenbindungsausdrücke. Die statische Methode DataBinder.Eval kann spät gebundene Datenbindungsausdrücke auswerten und als Zeichenfolge darstellen. Diese Methode DataBinder.Eval erhält zwei Parameter. Bei der Verwendung innerhalb einer Vorlage wird als erster Parameter stets das Objekt Container.DataItem angegeben. Der zweite Parameter enthält den Feldnamen als String.


Galileo Computing

12.10.7 Die Ereignisse des Repeater-Steuerelements auswerten  toptop

Abgesehen von den Ereignissen, die bereits die Basisklasse Control definiert, bietet das Repeater-Steuerelement drei Ereignisse:

gp  ItemCommand tritt ein, wenn innerhalb des Repeater-Elements eine Schaltfläche angeklickt wird.
gp  ItemCreated tritt ein, wenn im Repeater-Steuerelement ein Element erstellt wird.
gp  ItemDataBound tritt ein, nachdem ein Element an Daten gebunden, aber bevor es auf der Seite gerendert wurde.

db_22.aspx demonstriert, wie Sie innerhalb eines Repeater-Steuerelements in jeder Zeile eine Schaltfläche hinzufügen können. Wenn der Anwender eine Schaltfläche anklickt, wird unter der Tabelle die gewählte Nummer ausgegeben. Wenn die technischen Voraussetzungen gegeben sind, ließe sich hier eine Anwendung erstellen, die auf Mausklick die gewünschte Nummer wählt (siehe Abbildung 12.21).

<!-- db_22.aspx --> 
<%@ Page Language="VB" Debug="True" Strict="True" 
         EnableViewstate="true" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.OleDb" %>
<script runat="server">
Sub Page_Load (ByVal Sender As Object, _
               ByVal E As EventArgs)
   If Not IsPostBack Then
      Dim connStr As String 
      connStr = "Provider=Microsoft.Jet.OLEDB.4.0;"
      connStr += _
  "Data Source=C:\ASPdotNETBuch\Listings\Nordwind.mdb;"
      ' Verbindung zur Datenbank herstellen
      Dim conn As New OleDbConnection(connStr)
      conn.Open()
      Dim sql As String
      sql = "SELECT * FROM Versandfirmen"
      Dim cmd As New OleDbCommand(sql, conn)
      Dim myDataReader As OleDbDataReader
      myDataReader = cmd.ExecuteReader()
      myRepeat.DataSource = myDataReader
      myRepeat.DataBind()
      myDataReader.Close()
      conn.Close()
   End If               
End Sub

Public Sub myRepeat_ItemCommand _ 
                 (ByVal sender As Object, _
                  ByVal e As RepeaterCommandEventArgs) 
   ausgabe.innerHTML = "Anruf bei dieser Nummer: " _
           & CType(e.CommandSource, Button).Text
End Sub    

</script>
<html><head><title>
Repeater-Steuerelement mit ItemCommand-Ereignis
</title></head>
<body>
<h3>Repeater-Steuerelement mit ItemCommand-Ereignis
</h3>
<form runat="server">
<asp:repeater id="myRepeat" runat="server" 
              OnItemCommand="myRepeat_ItemCommand" >
   
   <HeaderTemplate>
      Versandfirmen mit Tel-Nr.: <table border="0">
   </HeaderTemplate>
   
   <ItemTemplate>
      <tr><td><%# DataBinder.Eval _
                      (Container.DataItem, "Firma") %>
      <td><asp:Button runat="server" Text=
'<%# DataBinder.Eval(Container.DataItem, "Telefon") %>'
           />                            
   </ItemTemplate>

   <FooterTemplate>
      </table>
   </FooterTemplate>
         
</asp:repeater>
<p runat="server" id="ausgabe" />
</form></body></html>

Abbildung
Hier klicken, um das Bild zu Vergrößern

Abbildung 12.21 Jeder Eintrag erhält eine eigene Schaltfläche.

db_22.aspx verwendet für die Vorlagen des Repeater-Steuerelements eine Tabellenstruktur. Die Schaltfläche in der zweiten Spalte wird mit Hilfe eines Button-Steuerelements erzeugt. Für die Beschriftung der Schaltfläche wird der bereits bekannte Datenbindungsausdruck verwendet:

<asp:Button runat="server" Text=
'<%# DataBinder.Eval(Container.DataItem, "Telefon") %>'  />        

Beachten Sie die unterschiedlichen Anführungszeichen. Dem Attribut Text wird sein Wert mit Hilfe einfacher Anführungszeichen zugewiesen. Auf diese Weise können innerhalb des Datenbindungsausdrucks doppelte Anführungszeichen verwendet werden.

Im Repeater-Element wird mit OnItemCommand="myRepeat_ItemCommand" die zugehörige Prozedur für die Ereignisbehandlung zugewiesen. Diese Prozedur gibt die gewählte Nummer unter der Tabelle aus.

Public Sub myRepeat_ItemCommand _ 
                 (ByVal sender As Object, _
                  ByVal e As RepeaterCommandEventArgs) 
   ausgabe.innerHTML = "Anruf bei dieser Nummer: " _
           & CType(e.CommandSource, Button).Text
End Sub

Der Ereignisprozedur myRepeat_ItemCommand wird ein Objekt vom Typ RepeaterCommandEventArgs als Parameter übergeben. Über dessen Eigenschaft CommandSource ist die auslösende Schaltfläche verfügbar. Nach der Konvertierung in ein Button-Objekt mit CType(e.CommandSource, Button) kann die Prozedur auf die Text-Eigenschaft zugreifen.

Eine weitere Änderung betrifft die Page-Deklaration und die Prozedur Page_Load. db_21.aspx hat die Option EnableViewState="false" verwendet, um den generierten HTML-Code so knapp wie möglich zu halten. Das war möglich, weil der Inhalt der Seite bei jedem Laden erneut generiert wurde.

db_22.aspx erstellt den Inhalt der Seite aber nur beim erstmaligen Laden, denn die Seite verwendet die If-Abfrage If Not IsPostBack ... Bei einem Postback sollen die Inhalte statt dessen aus dem Viewstate genommen werden, so dass jetzt in der Page-Deklaration die Option EnableViewState="true" verwendet werden muss. Würde diese Option auf false gelassen, wäre die Seite bei einem Postback leer.

  

Einstieg in VB.NET

VB.NET

Einstieg in C#

Visual C#

VB.NET und Datenbanken

Einstieg in XML




Copyright © Galileo Press GmbH 2003
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.


[Galileo Computing]

Galileo Press GmbH, Gartenstraße 24, 53229 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, info@galileo-press.de