Freigeben über


Eine Übersicht über das Einfügen, Aktualisieren und Löschen von Daten (C#)

von Scott Mitchell

PDF herunterladen

In diesem Lernprogramm erfahren Sie, wie Sie die Methoden Insert(), Update() und Delete() einer ObjectDataSource den Methoden von BLL-Klassen zuordnen und wie Sie die GridView-, DetailsView- und FormView-Steuerelemente konfigurieren, um Datenänderungsfunktionen bereitzustellen.

Einführung

In den vergangenen Lernprogrammen haben wir untersucht, wie Daten mithilfe der Steuerelemente GridView, DetailsView und FormView auf einer ASP.NET Seite angezeigt werden. Diese Steuerelemente funktionieren einfach mit ihnen bereitgestellten Daten. In der Regel greifen diese Steuerelemente mithilfe eines Datenquellensteuerelements, wie dem ObjectDataSource, auf Daten zu. Wir haben gesehen, wie die ObjectDataSource als Proxy zwischen der ASP.NET Seite und den zugrunde liegenden Daten fungiert. Wenn eine GridView Daten anzeigen muss, ruft sie die Methode der ObjectDataSource Select() auf, die wiederum eine Methode aus unserer Business Logic Layer (BLL) aufruft, die eine Methode im entsprechenden Data Access Layer (DAL) TableAdapter aufruft, was wiederum eine SELECT Abfrage an die Northwind-Datenbank sendet.

Denken Sie daran, dass Visual Studio beim Erstellen der TableAdapters im DAL in unserem ersten Lernprogramm automatisch Methoden zum Einfügen, Aktualisieren und Löschen von Daten aus der zugrunde liegenden Datenbanktabelle hinzugefügt hat. Darüber hinaus haben wir beim Erstellen einer Geschäftslogikebene Methoden in der BLL entwickelt, die diese Datenänderungs-DAL-Methoden aufgerufen haben.

Zusätzlich zu seiner Select() Methode verfügt objectDataSource auch über Insert(), Update()und Delete() Methoden. Wie die Select()-Methode können diese drei Methoden in einem zugrunde liegenden Objekt zugeordnet werden. Wenn sie zum Einfügen, Aktualisieren oder Löschen von Daten konfiguriert sind, bieten die Steuerelemente GridView, DetailsView und FormView eine Benutzeroberfläche zum Ändern der zugrunde liegenden Daten. Diese Benutzeroberfläche ruft die Insert()Methoden Update()und Methoden Delete() der ObjectDataSource auf, die dann die zugeordneten Methoden des zugrunde liegenden Objekts aufrufen (siehe Abbildung 1).

Die Methoden

Abbildung 1: Die Methoden Insert(), Update() und Delete() der ObjectDataSource dienen als Proxy in der BLL (Klicken, um das Bild in voller Größe anzuzeigen)

In diesem Lernprogramm erfahren Sie, wie Sie die ObjectDataSource-Methoden Insert(), Update() und Delete() Methoden von Klassen in der BLL zuordnen und die Steuerelemente GridView, DetailsView und FormView konfigurieren, um Funktionen zur Datenänderung bereitzustellen.

Schritt 1: Erstellen der Webseiten für die Anleitungen "Einfügen", "Aktualisieren" und "Löschen"

Bevor wir mit dem Einfügen, Aktualisieren und Löschen von Daten beginnen, nehmen wir uns zunächst einen Moment Zeit, um die ASP.NET Seiten in unserem Websiteprojekt zu erstellen, die wir für dieses Lernprogramm und die nächsten benötigen. Beginnen Sie mit dem Hinzufügen eines neuen Ordners mit dem Namen EditInsertDelete. Fügen Sie als Nächstes die folgenden ASP.NET Seiten zu diesem Ordner hinzu, und stellen Sie sicher, dass jede Seite der Site.master Gestaltungsvorlage zugeordnet wird:

  • Default.aspx
  • Basics.aspx
  • DataModificationEvents.aspx
  • ErrorHandling.aspx
  • UIValidation.aspx
  • CustomizedUI.aspx
  • OptimisticConcurrency.aspx
  • ConfirmationOnDelete.aspx
  • UserLevelAccess.aspx

Hinzufügen der ASP.NET Seiten für die datenänderungsbezogenen Lernprogramme

Abbildung 2: Hinzufügen der ASP.NET Seiten für die datenänderungsbezogenen Lernprogramme

Wie in den anderen Ordnern Default.aspx werden im EditInsertDelete Ordner die Lernprogramme im zugehörigen Abschnitt aufgelistet. Erinnern Sie sich daran, dass das SectionLevelTutorialListing.ascx Benutzersteuerelement diese Funktionalität bereitstellt. Fügen Sie daher dieses Benutzersteuerelement zu Default.aspx hinzu, indem Sie es aus dem Projektmappen-Explorer in die Seitenentwurfsansicht ziehen.

Hinzufügen des SectionLevelTutorialListing.ascx-Benutzersteuerelements zu Default.aspx

Abbildung 3: Hinzufügen des SectionLevelTutorialListing.ascx Benutzersteuerelements zu Default.aspx (Klicken, um das Bild in voller Größe anzuzeigen)

Fügen Sie schließlich die Seiten als Einträge zur Web.sitemap Datei hinzu. Fügen Sie insbesondere das folgende Markup nach der angepassten Formatierung <siteMapNode>hinzu:

<siteMapNode title="Editing, Inserting, and Deleting"
    url="~/EditInsertDelete/Default.aspx"
    description="Samples of Reports that Provide Editing, Inserting,
                  and Deleting Capabilities">
    <siteMapNode url="~/EditInsertDelete/Basics.aspx"
        title="Basics"
        description="Examines the basics of data modification with the
                      GridView, DetailsView, and FormView controls." />
    <siteMapNode url="~/EditInsertDelete/DataModificationEvents.aspx"
        title="Data Modification Events"
        description="Explores the events raised by the ObjectDataSource
                      pertinent to data modification." />
    <siteMapNode url="~/EditInsertDelete/ErrorHandling.aspx"
        title="Error Handling"
        description="Learn how to gracefully handle exceptions raised
                      during the data modification workflow." />
    <siteMapNode url="~/EditInsertDelete/UIValidation.aspx"
        title="Adding Data Entry Validation"
        description="Help prevent data entry errors by providing validation." />
    <siteMapNode url="~/EditInsertDelete/CustomizedUI.aspx"
        title="Customize the User Interface"
        description="Customize the editing and inserting user interfaces." />
    <siteMapNode url="~/EditInsertDelete/OptimisticConcurrency.aspx"
        title="Optimistic Concurrency"
        description="Learn how to help prevent simultaneous users from
                      overwritting one another s changes." />
    <siteMapNode url="~/EditInsertDelete/ConfirmationOnDelete.aspx"
        title="Confirm On Delete"
        description="Prompt a user for confirmation when deleting a record." />
    <siteMapNode url="~/EditInsertDelete/UserLevelAccess.aspx"
        title="Limit Capabilities Based on User"
        description="Learn how to limit the data modification functionality
                      based on the user role or permissions." />
</siteMapNode>

Nehmen Sie sich nach dem Aktualisieren Web.sitemap einen Moment Zeit, um die Tutorials-Website in einem Browser anzuzeigen. Das Menü auf der linken Seite enthält jetzt Elemente für die Bearbeitung, das Einfügen und Löschen von Lernprogrammen.

Die Websiteübersicht enthält jetzt Einträge für das Bearbeiten, Einfügen und Löschen von Lernprogrammen.

Abbildung 4: Die Websiteübersicht enthält jetzt Einträge für das Bearbeiten, Einfügen und Löschen von Lernprogrammen.

Schritt 2: Hinzufügen und Konfigurieren des ObjectDataSource-Steuerelements

Da sich gridView, DetailsView und FormView in ihren Datenänderungsfunktionen und -layouts unterscheiden, untersuchen wir die einzelnen Elemente einzeln. Anstatt jedes Steuerelement mit einer eigenen ObjectDataSource zu verwenden, erstellen wir einfach eine einzelne ObjectDataSource, die alle drei Steuerelementbeispiele freigeben können.

Öffnen Sie die Basics.aspx Seite, ziehen Sie eine ObjectDataSource aus der Toolbox in den Designer, und klicken Sie auf den Link "Datenquelle konfigurieren" aus dem Smarttag. Da es sich ProductsBLL um die einzige BLL-Klasse handelt, die Bearbeitungs-, Einfüge- und Löschmethoden bereitstellt, konfigurieren Sie die ObjectDataSource so, dass diese Klasse verwendet wird.

Konfigurieren der ObjectDataSource für die Verwendung der ProductsBLL-Klasse

Abbildung 5: Konfigurieren der ObjectDataSource für die Verwendung der ProductsBLL Klasse (Klicken Sie hier, um das Bild in voller Größe anzuzeigen)

Auf dem nächsten Bildschirm können wir angeben, welche Methoden der ProductsBLL Klasse den ObjectDataSource-Dateien Select()Insert()Update()zugeordnet sind, und Delete() indem Sie die entsprechende Registerkarte auswählen und die Methode aus der Dropdownliste auswählen. Abbildung 6, die Ihnen inzwischen vertraut sein dürfte, verknüpft die Methode von ObjectDataSource Select() mit der Methode der ProductsBLL-Klasse GetProducts(). Die Insert(), Update(), und Delete()-Methoden können durch Auswahl der entsprechenden Registerkarte in der Leiste oben konfiguriert werden.

Alle Produkte von ObjectDataSource zurückgeben

Abbildung 6: Gibt die ObjectDataSource alle Produkte zurück (Klicken Sie hier, um das Bild in voller Größe anzuzeigen)

Abbildung 7, 8 und 9 zeigen die Registerkarten UPDATE, INSERT und DELETE von ObjectDataSource an. Konfigurieren Sie diese Registerkarten so, dass die Methoden Insert(), Update() und Delete() jeweils die Methoden UpdateProduct, AddProduct und DeleteProduct der Klasse ProductsBLL aufrufen.

Zuordnen der Update()-Methode von ObjectDataSource zur UpdateProduct-Methode der ProductBLL-Klasse

Abbildung 7: Zuordnen der Methode von ObjectDataSource Update() zur Methode der ProductBLL Klasse UpdateProduct (Klicken, um das Bild in voller Größe anzuzeigen)

Zuordnung der Insert()-Methode des ObjectDataSource zur AddProduct-Methode der ProductBLL-Klasse

Abbildung 8: Zuordnen der Methode von ObjectDataSource Insert() zur Add-Methode ProductBLL der Product Klasse (Klicken, um das Bild in voller Größe anzuzeigen)

Zuordnen der Delete()-Methode von ObjectDataSource zur DeleteProduct-Methode der ProductBLL-Klasse

Abbildung 9: Zuordnen der Methode von ObjectDataSource Delete() zur Methode der ProductBLL Klasse DeleteProduct (Klicken, um das Bild in voller Größe anzuzeigen)

Möglicherweise haben Sie bemerkt, dass die Dropdownlisten in den Registerkarten UPDATE, INSERT und DELETE bereits diese Methoden ausgewählt haben. Dies verdanken wir der Verwendung von DataObjectMethodAttribute, die die Methoden von ProductsBLL dekoriert. Die DeleteProduct-Methode weist beispielsweise die folgende Signatur auf:

[System.ComponentModel.DataObjectMethodAttribute
    (System.ComponentModel.DataObjectMethodType.Delete, true)]
public bool DeleteProduct(int productID)
{
    ...
}

Das DataObjectMethodAttribute Attribut gibt den Zweck jeder Methode an, unabhängig davon, ob sie zum Auswählen, Einfügen, Aktualisieren oder Löschen dient und ob es sich um den Standardwert handelt. Wenn Sie diese Attribute beim Erstellen Ihrer BLL-Klassen weggelassen haben, müssen Sie die Methoden auf den Registerkarten UPDATE, INSERT und DELETE manuell auswählen.

Nachdem Sie sichergestellt haben, dass die entsprechenden ProductsBLL-Methoden den Methoden von ObjectDataSource Insert(), Update() und Delete() zugeordnet sind, klicken Sie auf "Fertig stellen", um den Assistenten abzuschließen.

Untersuchen des ObjectDataSource-Markups

Wechseln Sie nach dem Konfigurieren der ObjectDataSource über den Assistenten zur Quellansicht, um das generierte deklarative Markup zu untersuchen. Das <asp:ObjectDataSource> Tag gibt das zugrunde liegende Objekt und die aufzurufenden Methoden an. Darüber hinaus gibt es DeleteParameters, UpdateParameters und InsertParameters, die den Eingabeparametern der Methoden AddProduct, UpdateProduct und DeleteProduct der ProductsBLL-Klasse zugeordnet sind.

<asp:ObjectDataSource ID="ObjectDataSource1" runat="server"
    DeleteMethod="DeleteProduct" InsertMethod="AddProduct"
    OldValuesParameterFormatString="original_{0}" SelectMethod="GetProducts"
    TypeName="ProductsBLL" UpdateMethod="UpdateProduct">
    <DeleteParameters>
        <asp:Parameter Name="productID" Type="Int32" />
    </DeleteParameters>
    <UpdateParameters>
        <asp:Parameter Name="productName" Type="String" />
        <asp:Parameter Name="supplierID" Type="Int32" />
        <asp:Parameter Name="categoryID" Type="Int32" />
        <asp:Parameter Name="quantityPerUnit" Type="String" />
        <asp:Parameter Name="unitPrice" Type="Decimal" />
        <asp:Parameter Name="unitsInStock" Type="Int16" />
        <asp:Parameter Name="unitsOnOrder" Type="Int16" />
        <asp:Parameter Name="reorderLevel" Type="Int16" />
        <asp:Parameter Name="discontinued" Type="Boolean" />
        <asp:Parameter Name="productID" Type="Int32" />
    </UpdateParameters>
    <InsertParameters>
        <asp:Parameter Name="productName" Type="String" />
        <asp:Parameter Name="supplierID" Type="Int32" />
        <asp:Parameter Name="categoryID" Type="Int32" />
        <asp:Parameter Name="quantityPerUnit" Type="String" />
        <asp:Parameter Name="unitPrice" Type="Decimal" />
        <asp:Parameter Name="unitsInStock" Type="Int16" />
        <asp:Parameter Name="unitsOnOrder" Type="Int16" />
        <asp:Parameter Name="reorderLevel" Type="Int16" />
        <asp:Parameter Name="discontinued" Type="Boolean" />
    </InsertParameters>
</asp:ObjectDataSource>

Die ObjectDataSource enthält einen Parameter für jeden der Eingabeparameter ihrer zugehörigen Methoden, ähnlich wie eine Liste von SelectParameter n vorhanden ist, wenn die ObjectDataSource so konfiguriert ist, dass eine ausgewählte Methode aufgerufen wird, die einen Eingabeparameter erwartet, z. B. GetProductsByCategoryID(categoryID). Wie wir in Kürze sehen werden, werden die Werte für diese DeleteParameters, UpdateParameters und InsertParameters automatisch von GridView, DetailsView und FormView festgelegt, bevor die Insert()-, Update()- oder Delete()-Methode der ObjectDataSource aufgerufen wird. Diese Werte können auch programmgesteuert nach Bedarf festgelegt werden, wie wir in einem zukünftigen Tutorial besprechen werden.

Ein Nebeneffekt der Konfiguration von ObjectDataSource mit Hilfe des Assistenten ist, dass Visual Studio die Eigenschaft OldValuesParameterFormatString auf original_{0} setzt. Dieser Eigenschaftswert wird verwendet, um die ursprünglichen Werte der zu bearbeitenden Daten einzuschließen und ist in zwei Szenarien nützlich:

  • Wenn Benutzer beim Bearbeiten eines Datensatzes den Primärschlüsselwert ändern können. In diesem Fall müssen sowohl der neue Primärschlüsselwert als auch der ursprüngliche Primärschlüsselwert angegeben werden, damit der Datensatz mit dem ursprünglichen Primärschlüsselwert gefunden und dessen Wert entsprechend aktualisiert wird.
  • Bei Verwendung optimistischer Parallelität. Optimistische Parallelität ist eine Technik, um sicherzustellen, dass zwei gleichzeitige Benutzer die Änderungen eines anderen nicht überschreiben und das Thema für ein zukünftiges Lernprogramm sind.

Die OldValuesParameterFormatString Eigenschaft gibt den Namen der Eingabeparameter in den Aktualisierungs- und Löschmethoden des zugrunde liegenden Objekts für die ursprünglichen Werte an. Wir werden diese Eigenschaft und ihren Zweck genauer besprechen, wenn wir optimistische Parallelität untersuchen. Ich bringe es jetzt jedoch auf, da unsere BLL-Methoden nicht die ursprünglichen Werte erwarten und daher wichtig ist, dass wir diese Eigenschaft entfernen. Wenn die OldValuesParameterFormatString-Eigenschaft auf einen anderen Wert als den Standardwert ({0}) festgelegt wird, tritt ein Fehler auf, wenn ein Daten-Websteuerelement versucht, die Update()- oder Delete()-Methoden von ObjectDataSource aufzurufen, da die ObjectDataSource versucht, sowohl die UpdateParameters- als auch die DeleteParameters-ursprünglichen Wertparameter zu übergeben.

Wenn dies an diesem Punkt nicht besonders klar ist, keine Sorge, wir werden diese Eigenschaft und ihre Nützlichkeit in einem zukünftigen Tutorial untersuchen. Vorerst müssen Sie diese Eigenschaftsdeklaration nur vollständig aus der deklarativen Syntax entfernen oder den Wert auf den Standardwert ({0}) festlegen.

Hinweis

Wenn Sie einfach den OldValuesParameterFormatString Eigenschaftswert aus dem Eigenschaftenfenster in der Entwurfsansicht löschen, ist die Eigenschaft weiterhin in der deklarativen Syntax vorhanden, aber auf eine leere Zeichenfolge festgelegt. Dies wird leider immer noch zu dem oben erörterten Problem führen. Entfernen Sie daher entweder die Eigenschaft vollständig aus der deklarativen Syntax, oder legen Sie den Wert aus der Eigenschaftenfenster auf den Standardwert fest. {0}

Schritt 3: Hinzufügen eines Datenwebsteuerelements und dessen Konfiguration zur Datenbearbeitung

Nachdem die ObjectDataSource der Seite hinzugefügt und konfiguriert wurde, können wir der Seite Datenwebsteuerelemente hinzufügen, um die Daten anzuzeigen und dem Endbenutzer eine Möglichkeit zum Ändern der Daten bereitzustellen. Wir werden die GridView, DetailsView und FormView separat betrachten, da sich diese Datenwebsteuerelemente in ihren Datenänderungsfunktionen und der Konfiguration unterscheiden.

Wie wir im restlichen Teil dieses Artikels sehen, ist das Hinzufügen von sehr einfachen Bearbeitungs-, Einfüge- und Löschunterstützung über die GridView-, DetailsView- und FormView-Steuerelemente wirklich so einfach wie das Überprüfen einiger Kontrollkästchen. Es gibt viele Subtilitäten und Edge Cases in der realen Welt, die die Bereitstellung solcher Funktionalität komplizierter machen als nur Point-and-Click. Dieses Lernprogramm konzentriert sich jedoch ausschließlich auf den Nachweis einfacher Datenänderungsfunktionen. Zukünftige Lernprogramme werden Bedenken untersuchen, die zweifellos in einer realen Umgebung auftreten werden.

Löschen von Daten aus der GridView

Ziehen Sie zunächst eine GridView aus der Toolbox auf den Designer. Binden Sie als Nächstes die ObjectDataSource an die GridView, indem Sie diese aus der Dropdownliste im Smarttag der GridView auswählen. An diesem Punkt lautet das deklarative Markup von GridView:

<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
    DataKeyNames="ProductID" DataSourceID="ObjectDataSource1">
    <Columns>
        <asp:BoundField DataField="ProductID" HeaderText="ProductID"
            InsertVisible="False"
            ReadOnly="True" SortExpression="ProductID" />
        <asp:BoundField DataField="ProductName" HeaderText="ProductName"
            SortExpression="ProductName" />
        <asp:BoundField DataField="SupplierID" HeaderText="SupplierID"
           SortExpression="SupplierID" />
        <asp:BoundField DataField="CategoryID" HeaderText="CategoryID"
           SortExpression="CategoryID" />
        <asp:BoundField DataField="QuantityPerUnit"
           HeaderText="QuantityPerUnit"
           SortExpression="QuantityPerUnit" />
        <asp:BoundField DataField="UnitPrice" HeaderText="UnitPrice"
           SortExpression="UnitPrice" />
        <asp:BoundField DataField="UnitsInStock"
           HeaderText="UnitsInStock" SortExpression="UnitsInStock" />
        <asp:BoundField DataField="UnitsOnOrder"
           HeaderText="UnitsOnOrder" SortExpression="UnitsOnOrder" />
        <asp:BoundField DataField="ReorderLevel"
           HeaderText="ReorderLevel" SortExpression="ReorderLevel" />
        <asp:CheckBoxField DataField="Discontinued"
           HeaderText="Discontinued" SortExpression="Discontinued" />
        <asp:BoundField DataField="CategoryName"
           HeaderText="CategoryName" ReadOnly="True"
            SortExpression="CategoryName" />
        <asp:BoundField DataField="SupplierName"
            HeaderText="SupplierName" ReadOnly="True"
            SortExpression="SupplierName" />
    </Columns>
</asp:GridView>

Das Binden von GridView an ObjectDataSource über das Smarttag hat zwei Vorteile:

  • BoundFields und CheckBoxFields werden automatisch für jedes der felder erstellt, die von ObjectDataSource zurückgegeben werden. Darüber hinaus werden die Eigenschaften "BoundField" und "CheckBoxField" basierend auf den Metadaten des zugrunde liegenden Felds festgelegt. Beispielsweise sind die Felder ProductID, CategoryName und SupplierName im ProductsDataTable als schreibgeschützt gekennzeichnet und sollten daher beim Bearbeiten nicht aktualisiert werden. Um dies zu berücksichtigen, werden die ReadOnly-Eigenschaften dieser BoundFields auf true gesetzt.
  • Die DataKeyNames-Eigenschaft wird den Primärschlüsselfeldern des zugrunde liegenden Objekts zugewiesen. Dies ist für die Verwendung von GridView zum Bearbeiten oder Löschen von Daten unerlässlich, da diese Eigenschaft das Feld (oder die Gruppe von Feldern) angibt, das jeden Datensatz eindeutig identifiziert. Weitere Informationen zur DataKeyNames-Eigenschaft finden Sie im Tutorial „Master/Detail mit einem auswählbaren Master-GridView und DetailView“.

Die GridView kann zwar über das Eigenschaftenfenster oder deklarative Syntax an die ObjectDataSource gebunden werden, jedoch müssen Sie das entsprechende BoundField und DataKeyNames-Markup manuell hinzufügen.

Das GridView-Steuerelement bietet integrierte Unterstützung für die Bearbeitung und Löschung auf Zeilenebene. Durch das Konfigurieren einer GridView zur Unterstützung des Löschens wird eine Spalte mit Schaltflächen zum Löschen hinzugefügt. Wenn der Endbenutzer auf die Schaltfläche "Löschen" für eine bestimmte Zeile klickt, folgt ein Postback, und die GridView führt die folgenden Schritte aus:

  1. Der Wert(n) der DeleteParameters ObjectDataSource wird zugewiesen.
  2. Die Methode von Delete() ObjectDataSource wird aufgerufen, und der angegebene Datensatz wird gelöscht.
  3. Das GridView-Objekt wird durch Aufrufen der Select() Methode erneut an die ObjectDataSource gebunden.

Die dem Feld(n) zugewiesenen DeleteParameters Werte sind die Werte DataKeyNames für die Zeile, auf deren Schaltfläche "Löschen" geklickt wurde. Daher ist es wichtig, dass die Eigenschaft eines GridView-Steuerelements DataKeyNames ordnungsgemäß festgelegt wird. Wenn sie fehlt, wird dem DeleteParameters Wert in Schritt 1 ein null Wert zugewiesen, der wiederum nicht zu gelöschten Datensätzen in Schritt 2 führt.

Hinweis

Die DataKeys Auflistung wird im GridView-Steuerelementzustand gespeichert, was bedeutet, dass die DataKeys Werte über postback hinweg gespeichert werden, auch wenn der Ansichtszustand von GridView deaktiviert wurde. Es ist jedoch sehr wichtig, dass der Ansichtszustand für GridViews aktiviert bleibt, die das Bearbeiten oder Löschen unterstützen (das Standardverhalten). Wenn Sie die GridView-Eigenschaft EnableViewState auf false festlegen, funktioniert das Bearbeitungs- und Löschverhalten für einen einzelnen Benutzer einwandfrei. Aber wenn mehrere Benutzer gleichzeitig Daten löschen, besteht die Möglichkeit, dass Benutzer versehentlich Datensätze löschen oder bearbeiten, die nicht beabsichtigt waren.

Diese Warnung gilt auch für DetailsViews und FormViews.

Wenn Sie einer GridView Löschfunktionen hinzufügen möchten, wechseln Sie einfach zu seinem Smarttag, und aktivieren Sie das Kontrollkästchen "Löschen aktivieren".

Aktivieren des Kontrollkästchens

Abbildung 10: Aktivieren des Kontrollkästchens "Löschen aktivieren"

Durch Aktivieren des Kontrollkästchens "Löschen aktivieren" aus dem Smarttag wird dem GridView ein CommandField hinzugefügt. Das CommandField rendert eine Spalte in gridView mit Schaltflächen zum Ausführen einer oder mehrerer der folgenden Aufgaben: Auswählen eines Datensatzes, Bearbeiten eines Datensatzes und Löschen eines Datensatzes. Wir haben bereits das CommandField im Tutorial Master/Detail mit einer auswählbaren Master-GridView und Detail-DetailView im Kontext der Auswahl von Datensätzen in Aktion gesehen.

Das CommandField enthält eine Reihe von ShowXButton Eigenschaften, die angeben, welche Reihe von Schaltflächen im CommandField angezeigt werden. Durch das Markieren des Kontrollkästchens "Löschen aktivieren" wird ein CommandField, dessen ShowDeleteButton-Eigenschaft true ist, zur Columns-Sammlung von GridView hinzugefügt.

<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
    DataKeyNames="ProductID" DataSourceID="ObjectDataSource1">
    <Columns>
        <asp:CommandField ShowDeleteButton="True" />
        ... BoundFields removed for brevity ...
    </Columns>
</asp:GridView>

An dieser Stelle, glauben Sie es oder nicht, sind wir mit dem Hinzufügen der Löschunterstützung zur GridView fertig! Wie in Abbildung 11 dargestellt, ist beim Besuch dieser Seite über einen Browser eine Spalte mit Schaltflächen zum Löschen vorhanden.

Das CommandField fügt eine Spalte mit Schaltflächen zum Löschen hinzu.

Abbildung 11: Das CommandField fügt eine Spalte mit Löschschaltflächen hinzu (Klicken Sie, um das Bild in voller Größe anzuzeigen)

Wenn Sie dieses Lernprogramm von Grund auf selbst erstellt haben, wird beim Testen dieser Seite durch Klicken auf die Schaltfläche "Löschen" eine Ausnahme ausgelöst. Lesen Sie weiter, um zu erfahren, warum diese Ausnahmen ausgelöst wurden und wie sie behoben werden.

Hinweis

Wenn Sie dem Download folgen, der dieses Lernprogramm begleitet, wurden diese Probleme bereits berücksichtigt. Ich möchte Sie jedoch ermutigen, die unten aufgeführten Details zu lesen, um Probleme zu identifizieren, die auftreten können, und geeignete Problemumgehungen.

Wenn Sie beim Versuch, ein Produkt zu löschen, eine Ausnahme erhalten, deren Meldung der folgenden ähnlich ist: "ObjectDataSource 'ObjectDataSource1' konnte keine nicht generische Methode 'DeleteProduct' mit den Parametern productID, original_ProductID finden", haben Sie wahrscheinlich vergessen, die Eigenschaft OldValuesParameterFormatString aus der ObjectDataSource zu entfernen. Mit der OldValuesParameterFormatString-Eigenschaft versucht die ObjectDataSource, sowohl die productID- als auch die original_ProductID-Eingabeparameter an die DeleteProduct-Methode zu übergeben. DeleteProductakzeptiert jedoch nur einen einzelnen Eingabeparameter, daher die Ausnahme. Durch das Entfernen der OldValuesParameterFormatString Eigenschaft (oder festlegen auf {0}) wird die ObjectDataSource angewiesen, nicht zu versuchen, den ursprünglichen Eingabeparameter zu übergeben.

Stellen Sie sicher, dass die OldValuesParameterFormatString-Eigenschaft gelöscht wurde.

Abbildung 12: Sicherstellen, dass die OldValuesParameterFormatString Eigenschaft gelöscht wurde (Klicken Sie hier, um das Bild in voller Größe anzuzeigen)

Selbst wenn Sie die OldValuesParameterFormatString-Eigenschaft entfernt haben, erhalten Sie beim Versuch, ein Produkt zu löschen, eine Ausnahme mit der Meldung: "Die DELETE-Anweisung steht mit der REFERENCE-Einschränkung 'FK_Order_Details_Products' in Konflikt." Die Northwind-Datenbank enthält eine Fremdschlüsseleinschränkung zwischen der Order Details- und der Products-Tabelle, was bedeutet, dass ein Produkt nicht aus dem System gelöscht werden kann, wenn in der Order Details-Tabelle mindestens ein Datensatz vorhanden ist. Da jedes Produkt in der Northwind-Datenbank mindestens einen Datensatz enthält Order Details, können wir keine Produkte löschen, bis wir zuerst die zugehörigen Auftragsdetails des Produkts löschen.

Eine Fremdschlüsseleinschränkung verbietet das Löschen von Produkten.

Abbildung 13: Eine Fremdschlüsseleinschränkung verbietet das Löschen von Produkten (Klicken, um das Bild in voller Größe anzuzeigen)

Für unser Lernprogramm löschen wir einfach alle Datensätze aus der Order Details Tabelle. In einer realen Anwendung müssten wir eine der folgenden Aktionen ausführen:

  • Verwenden Sie einen weiteren Bildschirm zur Verwaltung der Bestelldetailinformationen.
  • Erweitern Sie die DeleteProduct Methode, um Logik zum Löschen der Bestelldetails des angegebenen Produkts einzuschließen.
  • Ändern der SQL-Abfrage, die vom TableAdapter verwendet wird, um das Löschen der Bestelldetails des angegebenen Produkts einzuschließen

Löschen wir einfach alle Datensätze aus der Order Details Tabelle, um die Fremdschlüsseleinschränkung zu umgehen. Wechseln Sie in Visual Studio zum Server-Explorer, klicken Sie mit der rechten Maustaste auf den NORTHWND.MDF Knoten, und wählen Sie "Neue Abfrage" aus. Führen Sie dann im Abfragefenster die folgende SQL-Anweisung aus: DELETE FROM [Order Details]

Alle Datensätze aus der Tabelle

Abbildung 14: Löschen aller Datensätze aus der Order Details Tabelle (Klicken Sie hier, um das Bild in voller Größe anzuzeigen)

Nachdem die Order Details Tabelle geleert wurde, wird durch Klicken auf die Schaltfläche "Löschen" das Produkt fehlerfrei gelöscht. Wenn das Klicken auf die Schaltfläche "Löschen" das Produkt nicht entfernt, überprüfen Sie, ob die Eigenschaft von DataKeyNames bei der GridView auf das Primärschlüsselfeld (ProductID) gesetzt ist.

Hinweis

Wenn Sie auf die Schaltfläche "Löschen" klicken, folgt ein Postback, und der Datensatz wird gelöscht. Dies kann gefährlich sein, da es leicht ist, versehentlich auf die Schaltfläche "Löschen" der falschen Zeile zu klicken. In einem zukünftigen Lernprogramm erfahren Sie, wie Sie beim Löschen eines Datensatzes eine clientseitige Bestätigung hinzufügen.

Bearbeiten von Daten mit gridView

Zusammen mit dem Löschen bietet das GridView-Steuerelement auch integrierte Unterstützung für die Bearbeitung auf Zeilenebene. Durch das Konfigurieren einer GridView zur Unterstützung der Bearbeitung wird eine Spalte mit Bearbeitungsschaltflächen hinzugefügt. Aus Sicht des Endbenutzers bewirkt das Klicken auf die Schaltfläche "Bearbeiten" der Zeile, dass diese Zeile bearbeitbar wird und die Zellen in Textfelder umgewandelt werden, die die vorhandenen Werte enthalten, und die Schaltfläche "Bearbeiten" durch die Schaltflächen "Aktualisieren" und "Abbrechen" ersetzen. Nachdem sie ihre gewünschten Änderungen vorgenommen haben, kann der Endbenutzer auf die Schaltfläche "Aktualisieren" klicken, um die Änderungen zu übernehmen, oder auf die Schaltfläche "Abbrechen", um sie zu verwerfen. In beiden Fällen kehrt die GridView nach dem Klicken auf "Aktualisieren" oder "Abbrechen" zum Vorbearbeitungszustand zurück.

Aus unserer Sicht als Seitenentwickler, wenn der Endbenutzer auf die Schaltfläche "Bearbeiten" für eine bestimmte Zeile klickt, erfolgt ein Postback und die GridView führt die folgenden Schritte aus:

  1. Die GridView-Eigenschaft EditItemIndex wird dem Index der Zeile zugewiesen, auf deren Schaltfläche "Bearbeiten" geklickt wurde.
  2. Das GridView-Objekt wird durch Aufrufen der Select() Methode erneut an die ObjectDataSource gebunden.
  3. Der Zeilenindex, der dem EditItemIndex entspricht, wird im "Bearbeitungsmodus" gerendert. In diesem Modus wird die Schaltfläche "Bearbeiten" durch die Schaltflächen "Aktualisieren" und "Abbrechen" und "BoundFields" ersetzt, deren ReadOnly Eigenschaften "False" (Standard) als TextBox-Websteuerelemente gerendert werden, deren Text Eigenschaften den Werten der Datenfelder zugewiesen sind.

An diesem Punkt wird das Markup an den Browser zurückgegeben, sodass der Endbenutzer änderungen an den Daten der Zeile vornehmen kann. Wenn der Benutzer auf die Schaltfläche "Aktualisieren" klickt, wird ein Postback ausgelöst und GridView führt die folgenden Schritte aus:

  1. Dem Wert(n) des UpdateParameters ObjectDataSource werden die vom Endbenutzer in die Bearbeitungsoberfläche von GridView eingegebenen Werte zugewiesen.
  2. Die Methode von Update() ObjectDataSource wird aufgerufen, und der angegebene Datensatz wird aktualisiert.
  3. Das GridView-Objekt wird durch Aufrufen der Select() Methode erneut an die ObjectDataSource gebunden.

Die in Schritt 1 zugewiesenen UpdateParameters Primärschlüsselwerte stammen aus den in der DataKeyNames Eigenschaft angegebenen Werten, während die Nicht-Primärschlüsselwerte aus dem Text in den TextBox-Websteuerelementen für die bearbeitete Zeile stammen. Wie beim Löschen ist es wichtig, dass die Eigenschaft eines GridView-Steuerelements DataKeyNames ordnungsgemäß festgelegt wird. Fehlt dieser Wert, wird dem UpdateParameters Primärschlüsselwert in Schritt 1 ein null Wert zugewiesen, der wiederum nicht zu aktualisierten Datensätzen in Schritt 2 führt.

Bearbeitungsfunktionen können aktiviert werden, indem sie einfach das Kontrollkästchen "Bearbeitung aktivieren" im Smarttag von GridView aktivieren.

Aktivieren des Kontrollkästchens

Abbildung 15: Aktivieren des Kontrollkästchens "Bearbeitung aktivieren"

Wenn Sie das Kontrollkästchen "Bearbeitung aktivieren" aktivieren, wird bei Bedarf ein CommandField hinzugefügt und dessen ShowEditButton-Eigenschaft auf true festgelegt. Wie wir bereits gesehen haben, enthält das CommandField eine Reihe von ShowXButton Eigenschaften, die angeben, welche Reihe von Schaltflächen im CommandField angezeigt werden. Durch Aktivieren des Kontrollkästchens "Bearbeitung aktivieren" wird die ShowEditButton Eigenschaft zum vorhandenen CommandField hinzugefügt:

<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
    DataKeyNames="ProductID" DataSourceID="ObjectDataSource1">
    <Columns>
        <asp:CommandField ShowDeleteButton="True"
            ShowEditButton="True" />
        ... BoundFields removed for brevity ...
    </Columns>
</asp:GridView>

Das ist alles, was es gibt, um eine rudimentäre Bearbeitungsunterstützung hinzuzufügen. Wie in Abbildung 16 gezeigt, ist die Bearbeitungsschnittstelle eher unformatiert. Jedes BoundField, dessen ReadOnly Eigenschaft auf false (standardmäßig) festgelegt ist, wird als TextBox gerendert. Dazu gehören Felder wie CategoryID und SupplierID, die Schlüssel zu anderen Tabellen sind.

Durch Klicken auf die Schaltfläche

Abbildung 16: Klicken auf die Schaltfläche "Chai s Bearbeiten" zeigt die Zeile im Bearbeitungsmodus an (Klicken, um das Bild in voller Größe anzuzeigen)

Zusätzlich dazu, dass Benutzer direkt Fremdschlüsselwerte bearbeiten sollen, weist die Benutzeroberfläche der Bearbeitungsschnittstelle die folgenden Mängel auf:

  • Wenn der Benutzer ein CategoryID oder SupplierID eingibt, das in der Datenbank nicht vorhanden ist, verstößt der UPDATE gegen eine Fremdschlüsseleinschränkung, wodurch eine Ausnahme ausgelöst wird.
  • Die Bearbeitungsschnittstelle enthält keine Überprüfung. Wenn Sie keinen erforderlichen Wert (wie ProductName) angeben oder einen Zeichenfolgenwert eingeben, bei dem ein numerischer Wert erwartet wird (z. B. "Zu viel!" in das Textfeld UnitPrice eingeben), wird eine Ausnahme ausgelöst. In einem zukünftigen Lernprogramm wird das Hinzufügen von Überprüfungssteuerelementen zur Bearbeitungs-Benutzeroberfläche untersucht.
  • Derzeit müssen alle Produktfelder, die nicht schreibgeschützt sind, in der GridView enthalten sein. Wenn wir ein Feld, sagen wir UnitPrice, aus der GridView entfernen würden, würde die GridView beim Aktualisieren der Daten den UnitPriceUpdateParameters-Wert nicht festlegen, wodurch der Datenbankdatensatz UnitPrice in einen NULL-Wert geändert würde. Wenn ein erforderliches Feld, wie z. B. ProductName, aus der GridView entfernt wird, wird die Aktualisierung mit derselben oben erwähnten Ausnahme "Spalte 'ProductName' lässt keine NULL-Werte zu" fehlschlagen.
  • Die Formatierung der Bearbeitungsschnittstelle lässt viel zu wünschen übrig. Dies UnitPrice wird mit vier Dezimalstellen angezeigt. Idealerweise würden die CategoryID- und SupplierID-Werte DropDownLists enthalten, die die Kategorien und Lieferanten im System auflisten.

Dies sind alle Mängel, mit denen wir jetzt leben müssen, werden aber in zukünftigen Lernprogrammen behandelt.

Einfügen, Bearbeiten und Löschen von Daten mit der DetailsView

Wie wir in früheren Lernprogrammen gesehen haben, zeigt das DetailView-Steuerelement jeweils einen Datensatz an und ermöglicht wie gridView das Bearbeiten und Löschen des aktuell angezeigten Datensatzes. Sowohl die Benutzererfahrung des Endbenutzers beim Bearbeiten und Löschen von Elementen aus einer DetailsView als auch der Workflow auf der ASP.NET-Seite ist identisch mit der von GridView. Der Unterschied zwischen DetailsView und GridView besteht darin, dass sie auch integrierte Unterstützung für das Einfügen bietet.

Um die Datenänderungsfunktionen von GridView zu veranschaulichen, fügen Sie zunächst eine DetailsView zur Basics.aspx Seite oberhalb der vorhandenen GridView hinzu und binden sie über das Smarttag von DetailsView an die vorhandene ObjectDataSource. Löschen Sie als Nächstes die Height und Width Eigenschaften von DetailsView, und aktivieren Sie die Option "Paging aktivieren" vom Smart-Tag. Um die Unterstützung für Bearbeitung, Einfügen und Löschen zu aktivieren, aktivieren Sie einfach die Kontrollkästchen "Bearbeiten aktivieren", "Einfügen aktivieren" und "Löschen" im Smarttag.

Screenshot des Fensters

Abbildung 17: Konfigurieren der DetailsView zur Unterstützung von Bearbeitung, Einfügen und Löschen

Wie bei gridView fügt das Hinzufügen von Bearbeitungs-, Einfüge- oder Löschunterstützung ein CommandField zur DetailsView hinzu, wie die folgende deklarative Syntax zeigt:

<asp:DetailsView ID="DetailsView1" runat="server" AutoGenerateRows="False"
    DataKeyNames="ProductID" DataSourceID="ObjectDataSource1" AllowPaging="True">
    <Fields>
        <asp:BoundField DataField="ProductID"
            HeaderText="ProductID" InsertVisible="False"
            ReadOnly="True" SortExpression="ProductID" />
        <asp:BoundField DataField="ProductName"
            HeaderText="ProductName" SortExpression="ProductName" />
        <asp:BoundField DataField="SupplierID" HeaderText="SupplierID"
            SortExpression="SupplierID" />
        <asp:BoundField DataField="CategoryID" HeaderText="CategoryID"
            SortExpression="CategoryID" />
        <asp:BoundField DataField="QuantityPerUnit"
            HeaderText="QuantityPerUnit"
            SortExpression="QuantityPerUnit" />
        <asp:BoundField DataField="UnitPrice"
            HeaderText="UnitPrice" SortExpression="UnitPrice" />
        <asp:BoundField DataField="UnitsInStock"
            HeaderText="UnitsInStock" SortExpression="UnitsInStock" />
        <asp:BoundField DataField="UnitsOnOrder"
            HeaderText="UnitsOnOrder" SortExpression="UnitsOnOrder" />
        <asp:BoundField DataField="ReorderLevel"
            HeaderText="ReorderLevel" SortExpression="ReorderLevel" />
        <asp:CheckBoxField DataField="Discontinued"
            HeaderText="Discontinued" SortExpression="Discontinued" />
        <asp:BoundField DataField="CategoryName"
            HeaderText="CategoryName" ReadOnly="True"
            SortExpression="CategoryName" />
        <asp:BoundField DataField="SupplierName"
            HeaderText="SupplierName" ReadOnly="True"
            SortExpression="SupplierName" />
        <asp:CommandField ShowDeleteButton="True"
            ShowEditButton="True" ShowInsertButton="True" />
    </Fields>
</asp:DetailsView>

Beachten Sie, dass für "DetailsView" das CommandField standardmäßig am Ende der Columns-Auflistung angezeigt wird. Da die Felder von DetailsView als Zeilen gerendert werden, wird das CommandField als Zeile mit den Schaltflächen "Einfügen", "Bearbeiten" und "Löschen" am unteren Rand der Detailansicht angezeigt.

Screenshot der Detailansicht mit dem CommandField, das als untere Zeile mit den Schaltflächen

Abbildung 18: Konfigurieren der Detailansicht zur Unterstützung von Bearbeitung, Einfügen und Löschen (Klicken, um das Bild in voller Größe anzuzeigen)

Durch Klicken auf die Schaltfläche "Löschen" wird die gleiche Abfolge von Ereignissen wie bei gridView gestartet: ein Postback; gefolgt von der DetailsView, die die ObjectDataSource DeleteParameters basierend auf den DataKeyNames Werten auffüllt, und mit einem Aufruf der ObjectDataSource-Methode Delete() abgeschlossen, die das Produkt tatsächlich aus der Datenbank entfernt. Die Bearbeitung in der DetailsView funktioniert auch in einer Weise, die mit der des GridView identisch ist.

Für das Einfügen wird dem Endbenutzer eine Schaltfläche "Neu" angezeigt, die beim Klicken die DetailsView im "Einfügemodus" rendert. Im "Einfügemodus" wird die Schaltfläche "Neu" durch die Schaltflächen "Einfügen" und "Abbrechen" ersetzt, und es werden nur die BoundFields angezeigt, deren InsertVisible Eigenschaft auf true (Standard) festgelegt ist. Datenfelder, die als automatisch inkrementell identifiziert wurden, wie ProductID, haben die InsertVisible-Eigenschaft auf false festgelegt, wenn die DetailsView über das Smarttag an die Datenquelle gebunden wird.

Wenn eine Datenquelle über das Smarttag an eine DetailsView gebunden wird, setzt Visual Studio die InsertVisible-Eigenschaft auf false nur bei auto-Inkrement-Feldern fest. Schreibgeschützte Felder wie CategoryName und SupplierName werden auf der Benutzeroberfläche "Einfügemodus" angezeigt, es sei denn, ihre InsertVisible Eigenschaft ist explizit auf false festgelegt. Nehmen Sie sich einen Moment Zeit, um die Eigenschaften dieser beiden Felder InsertVisible auf false, entweder über die deklarative Syntax von DetailsView oder über den Link "Felder bearbeiten" im Smarttag festzulegen. Abbildung 19 zeigt, wie die InsertVisible-Eigenschaften auf false festgelegt werden, indem auf den Link "Felder bearbeiten" geklickt wird.

Screenshot des Fensters

Abbildung 19: Northwind Traders bietet jetzt Acme Tea (Klicken Sie hier, um das Bild in voller Größe anzuzeigen)

Nachdem Sie die InsertVisible Eigenschaften festgelegt haben, zeigen Sie die Basics.aspx Seite in einem Browser an, und klicken Sie auf die Schaltfläche "Neu". Abbildung 20 zeigt die Detailansicht beim Hinzufügen eines neuen Getränks, Acme Tea, zu unserer Produktlinie.

Screenshot der Detailsansicht der Seite Basics.aspx in einem Webbrowser.

Abbildung 20: Northwind Traders bietet jetzt Acme Tea (Klicken Sie hier, um das Bild in voller Größe anzuzeigen)

Nachdem Sie die Details für Acme Tea eingegeben und auf die Schaltfläche "Einfügen" geklickt haben, folgt ein Postback, und der neue Datensatz wird der Products Datenbanktabelle hinzugefügt. Da diese DetailsView die Produkte in der Reihenfolge auflistet, in der sie in der Datenbanktabelle vorhanden sind, müssen wir zum letzten Produkt wechseln, um das neue Produkt anzuzeigen.

Details zu Acme Tea

Abbildung 21: Details für Acme Tea (Klicken Sie hier, um das Bild in voller Größe anzuzeigen)

Hinweis

Die Eigenschaft CurrentMode von DetailsView zeigt die gerade angezeigte Schnittstelle an und kann einen der folgenden Werte haben: Edit, Insert oder ReadOnly. Die DefaultMode-Eigenschaft gibt den Modus an, zu dem die DetailsView zurückkehrt, nachdem eine Bearbeitung oder ein Einfügevorgang abgeschlossen wurde und nützlich ist, um eine DetailsView anzuzeigen, die sich dauerhaft im Bearbeitungs- oder Einfügemodus befindet.

Die Point-and-Click-Einfüge- und Bearbeitungsfunktionen der DetailsView leiden unter den gleichen Einschränkungen wie die GridView: Der Benutzer muss vorhandene CategoryID- und SupplierID-Werte über ein Textfeld eingeben; der Schnittstelle fehlt es an einer Validierungslogik; alle Produktfelder, die keine NULL-Werte zulassen oder keinen Standardwert auf Datenbankebene festgelegt haben, müssen in die Einfügeschnittstelle aufgenommen werden, und so weiter.

Die Techniken, die wir untersuchen, um die Bearbeitungsschnittstelle von GridView in zukünftigen Artikeln zu erweitern und zu verbessern, können auch auf die Bearbeitungs- und Einfügeschnittstellen des DetailsView-Steuerelements angewendet werden.

Verwenden der FormView für eine flexiblere Benutzeroberfläche zur Datenänderung

FormView bietet integrierte Unterstützung für das Einfügen, Bearbeiten und Löschen von Daten, aber da es Vorlagen anstelle von Feldern verwendet, gibt es keinen Ort, um die BoundFields oder das CommandField hinzuzufügen, das von den GridView- und DetailsView-Steuerelementen verwendet wird, um die Datenänderungsschnittstelle bereitzustellen. Stattdessen müssen die Web-Interface-Steuerelemente, um Eingaben der Benutzer beim Hinzufügen eines neuen Elements oder beim Bearbeiten eines vorhandenen zu erfassen, zusammen mit den Schaltflächen "Neu", "Bearbeiten", "Löschen", "Einfügen", "Aktualisieren" und "Abbrechen" manuell zu den entsprechenden Vorlagen hinzugefügt werden. Glücklicherweise erstellt Visual Studio automatisch die erforderliche Schnittstelle, wenn die FormView über die Dropdownliste in seinem Smarttag an eine Datenquelle gebunden wird.

Um diese Techniken zu veranschaulichen, fügen Sie zunächst eine FormView zur Basics.aspx Seite hinzu, und binden Sie sie über das Smarttag von FormView bereits an die bereits erstellte ObjectDataSource. Dadurch werden ein EditItemTemplate, ein InsertItemTemplate und ein ItemTemplate für die FormView mit TextBox-Websteuerelementen zur Sammlung der Eingaben des Benutzers sowie Schaltflächen-Websteuerelementen für die Schaltflächen "Neu", "Bearbeiten", "Löschen", "Einfügen", "Aktualisieren" und "Abbrechen" generiert. Darüber hinaus wird die FormView-Eigenschaft DataKeyNames auf das Primärschlüsselfeld (ProductID) des Objekts festgelegt, das von ObjectDataSource zurückgegeben wird. Überprüfen Sie abschließend die Option "Paging aktivieren" im Smarttag von FormView.

Im Folgenden wird das deklarative Markup für die FormView ItemTemplate gezeigt, nachdem die FormView an die ObjectDataSource gebunden wurde. Standardmäßig ist jedes nicht boolesche Wertproduktfeld an die Text Eigenschaft eines Label-Websteuerelements gebunden, während jedes boolesche Wertfeld (Discontinued) an die Checked Eigenschaft eines deaktivierten CheckBox-Websteuerelements gebunden ist. Damit die Schaltflächen "Neu", "Bearbeiten" und "Löschen" bestimmtes FormView-Verhalten beim Klicken auslösen können, ist es zwingend erforderlich, dass ihre CommandName Werte auf New, Edit bzw. Delete gesetzt werden.

<asp:FormView ID="FormView1" runat="server" DataKeyNames="ProductID"
    DataSourceID="ObjectDataSource1" AllowPaging="True">
    <EditItemTemplate>
        ...
    </EditItemTemplate>
    <InsertItemTemplate>
        ...
    </InsertItemTemplate>
    <ItemTemplate>
        ProductID:
        <asp:Label ID="ProductIDLabel" runat="server"
            Text='<%# Eval("ProductID") %>'></asp:Label><br />
        ProductName:
        <asp:Label ID="ProductNameLabel" runat="server"
            Text='<%# Bind("ProductName") %>'>
        </asp:Label><br />
        SupplierID:
        <asp:Label ID="SupplierIDLabel" runat="server"
            Text='<%# Bind("SupplierID") %>'>
        </asp:Label><br />
        CategoryID:
        <asp:Label ID="CategoryIDLabel" runat="server"
            Text='<%# Bind("CategoryID") %>'>
        </asp:Label><br />
        QuantityPerUnit:
        <asp:Label ID="QuantityPerUnitLabel" runat="server"
            Text='<%# Bind("QuantityPerUnit") %>'>
        </asp:Label><br />
        UnitPrice:
        <asp:Label ID="UnitPriceLabel" runat="server"
            Text='<%# Bind("UnitPrice") %>'></asp:Label><br />
        UnitsInStock:
        <asp:Label ID="UnitsInStockLabel" runat="server"
            Text='<%# Bind("UnitsInStock") %>'>
        </asp:Label><br />
        UnitsOnOrder:
        <asp:Label ID="UnitsOnOrderLabel" runat="server"
            Text='<%# Bind("UnitsOnOrder") %>'>
        </asp:Label><br />
        ReorderLevel:
        <asp:Label ID="ReorderLevelLabel" runat="server"
            Text='<%# Bind("ReorderLevel") %>'>
        </asp:Label><br />
        Discontinued:
        <asp:CheckBox ID="DiscontinuedCheckBox" runat="server"
            Checked='<%# Bind("Discontinued") %>'
            Enabled="false" /><br />
        CategoryName:
        <asp:Label ID="CategoryNameLabel" runat="server"
            Text='<%# Bind("CategoryName") %>'>
        </asp:Label><br />
        SupplierName:
        <asp:Label ID="SupplierNameLabel" runat="server"
            Text='<%# Bind("SupplierName") %>'>
        </asp:Label><br />
        <asp:LinkButton ID="EditButton" runat="server"
            CausesValidation="False" CommandName="Edit"
            Text="Edit">
        </asp:LinkButton>
        <asp:LinkButton ID="DeleteButton" runat="server"
            CausesValidation="False" CommandName="Delete"
            Text="Delete">
        </asp:LinkButton>
        <asp:LinkButton ID="NewButton" runat="server"
            CausesValidation="False" CommandName="New"
            Text="New">
        </asp:LinkButton>
    </ItemTemplate>
</asp:FormView>

In Abbildung 22 ist die FormView ItemTemplate dargestellt, wenn sie über einen Browser angezeigt wird. Jedes Produktfeld wird mit den Schaltflächen "Neu", "Bearbeiten" und "Löschen" unten aufgeführt.

Die Defaut FormView ItemTemplate listet jedes Produktfeld zusammen mit den Schaltflächen

Abbildung 22: Die defaut FormView ItemTemplate listet jedes Produktfeld zusammen mit den Schaltflächen "Neu", "Bearbeiten" und "Löschen" auf (Klicken Sie, um das Bild in voller Größe anzuzeigen)

Wie bei GridView und DetailsView wird durch Klicken auf die Schaltfläche "Löschen" oder eine beliebige Schaltfläche, einen LinkButton oder ImageButton, deren CommandName-Eigenschaft auf "Delete" gesetzt ist, ein Rückruf ausgelöst, die Eigenschaft DeleteParameters von ObjectDataSource basierend auf dem Wert von DataKeyNames in FormView gefüllt und die Methode Delete() von ObjectDataSource aufgerufen.

Wenn auf die Schaltfläche "Bearbeiten" geklickt wird, wird ein Postback ausgelöst, und die Daten werden wieder an die EditItemTemplateBearbeitungsoberfläche gebunden, die für das Rendern der Bearbeitungsschnittstelle verantwortlich ist. Diese Schnittstelle enthält die Websteuerelemente zum Bearbeiten von Daten zusammen mit den Schaltflächen "Aktualisieren" und "Abbrechen". Die von Visual Studio generierte Standardeinstellung EditItemTemplate enthält eine Bezeichnung für alle automatisch inkrementellen Felder (ProductID), ein TextBox für jedes nicht boolesche Wertfeld und ein CheckBox für jedes boolesche Wertfeld. Dieses Verhalten ähnelt sehr den automatisch generierten BoundFields in den GridView- und DetailsView-Steuerelementen.

Hinweis

Ein kleines Problem mit der automatischen Generierung von FormView besteht darin, dass TextBox-Websteuerelemente für diejenigen Felder gerendert werden, die schreibgeschützt sind, wie zum Beispiel CategoryName und SupplierName. Wir werden sehen, wie sie dies in Kürze berücksichtigen.

Die TextBox-Steuerelemente in der EditItemTemplate haben ihre Eigenschaft Text mittels bidirektionaler Datenbindung an den Wert des entsprechenden Datenfelds gebunden. Bidirektionale Datenbindung, bezeichnet durch <%# Bind("dataField") %>, führt Datenbindung sowohl beim Binden von Daten an die Vorlage als auch beim Auffüllen der Parameter der ObjectDataSource zum Einfügen oder Bearbeiten von Datensätzen durch. Wenn der Benutzer auf die Schaltfläche "Bearbeiten" aus der ItemTemplateSchaltfläche klickt, gibt die Bind() Methode den angegebenen Datenfeldwert zurück. Nachdem der Benutzer seine Änderungen vorgenommen hat und auf "Aktualisieren" klickt, werden die zurückgegebenen Werte, die den angegebenen Datenfeldern Bind() entsprechen, auf die UpdateParameters des ObjectDataSource angewendet. Alternativ verwendet die unidirektionale Datenbindung, die mit <%# Eval("dataField") %> bezeichnet wird, nur die Datenfeldwerte, wenn Daten an das Template gebunden werden, und gibt die vom Benutzer eingegebenen Werte beim Postback nicht zurück an die Parameter der Datenquelle.

Das folgende deklarative Markup zeigt die FormViews EditItemTemplate. Beachten Sie, dass die Bind() Methode hier in der Datenbindungssyntax verwendet wird und dass die Websteuerelemente "Aktualisieren" und "Abbrechen"-Schaltflächen ihre CommandName Eigenschaften entsprechend festgelegt haben.

<asp:FormView ID="FormView1" runat="server" DataKeyNames="ProductID"
    DataSourceID="ObjectDataSource1" AllowPaging="True">
    <EditItemTemplate>
        ProductID:
        <asp:Label ID="ProductIDLabel1" runat="server"
          Text="<%# Eval("ProductID") %>"></asp:Label><br />
        ProductName:
        <asp:TextBox ID="ProductNameTextBox" runat="server"
          Text="<%# Bind("ProductName") %>">
        </asp:TextBox><br />
        SupplierID:
        <asp:TextBox ID="SupplierIDTextBox" runat="server"
          Text="<%# Bind("SupplierID") %>">
        </asp:TextBox><br />
        CategoryID:
        <asp:TextBox ID="CategoryIDTextBox" runat="server"
          Text="<%# Bind("CategoryID") %>">
        </asp:TextBox><br />
        QuantityPerUnit:
        <asp:TextBox ID="QuantityPerUnitTextBox" runat="server"
           Text="<%# Bind("QuantityPerUnit") %>">
        </asp:TextBox><br />
        UnitPrice:
        <asp:TextBox ID="UnitPriceTextBox" runat="server"
           Text="<%# Bind("UnitPrice") %>">
        </asp:TextBox><br />
        UnitsInStock:
        <asp:TextBox ID="UnitsInStockTextBox" runat="server"
           Text="<%# Bind("UnitsInStock") %>">
        </asp:TextBox><br />
        UnitsOnOrder:
        <asp:TextBox ID="UnitsOnOrderTextBox" runat="server"
           Text="<%# Bind("UnitsOnOrder") %>">
        </asp:TextBox><br />
        ReorderLevel:
        <asp:TextBox ID="ReorderLevelTextBox" runat="server"
           Text="<%# Bind("ReorderLevel") %>">
        </asp:TextBox><br />
        Discontinued:
        <asp:CheckBox ID="DiscontinuedCheckBox" runat="server"
            Checked="<%# Bind("Discontinued") %>" /><br />
        CategoryName:
        <asp:TextBox ID="CategoryNameTextBox" runat="server"
             Text="<%# Bind("CategoryName") %>">
        </asp:TextBox><br />
        SupplierName:
        <asp:TextBox ID="SupplierNameTextBox" runat="server"
             Text="<%# Bind("SupplierName") %>">
        </asp:TextBox><br />
        <asp:LinkButton ID="UpdateButton" runat="server"
            CausesValidation="True" CommandName="Update"
            Text="Update">
        </asp:LinkButton>
        <asp:LinkButton ID="UpdateCancelButton" runat="server"
            CausesValidation="False" CommandName="Cancel"
            Text="Cancel">
        </asp:LinkButton>
    </EditItemTemplate>
    <InsertItemTemplate>
        ...
    </InsertItemTemplate>
    <ItemTemplate>
        ...
    </ItemTemplate>
</asp:FormView>

Unsere EditItemTemplate wird zu diesem Zeitpunkt eine Ausnahme auslösen, wenn wir versuchen, sie zu verwenden. Das Problem besteht darin, dass die Felder CategoryName und SupplierName als TextBox-Websteuerelemente im EditItemTemplate gerendert werden. Diese Textfelder müssen entweder in Labels umgewandelt oder vollständig entfernt werden. Löschen wir sie einfach vollständig aus dem EditItemTemplate.

Abbildung 23 zeigt die FormView in einem Browser, nachdem auf die Schaltfläche "Bearbeiten" für "Chai" geklickt wurde. Beachten Sie, dass die SupplierName und CategoryName Felder, die im ItemTemplate angezeigt werden, nicht mehr vorhanden sind, da wir sie gerade aus der EditItemTemplate Datei entfernt haben. Wenn auf die Schaltfläche "Aktualisieren" geklickt wird, durchläuft die FormView dieselbe Abfolge von Schritten wie die GridView- und DetailsView-Steuerelemente.

Standardmäßig zeigt die EditItemTemplate jedes bearbeitbare Produktfeld als TextBox- oder CheckBox-Objekt an.

Abbildung 23: Standardmäßig wird jedes EditItemTemplate bearbeitbare Produktfeld als TextBox oder CheckBox angezeigt (Klicken Sie, um das Bild in voller Größe anzuzeigen)

Wenn auf die Schaltfläche "Einfügen" geklickt wird, erfolgt ein Postback des FormViews ItemTemplate. Allerdings sind keine Daten an die FormView gebunden, da ein neuer Datensatz hinzugefügt wird. Die InsertItemTemplate Schnittstelle enthält die Websteuerelemente zum Hinzufügen eines neuen Datensatzes zusammen mit den Schaltflächen "Einfügen" und "Abbrechen". Der von Visual Studio generierte Standardwert InsertItemTemplate enthält ein TextBox-Element für jedes nicht boolesche Wertfeld und ein CheckBox-Element für jedes boolesche Wertfeld, ähnlich der automatisch generierten EditItemTemplateSchnittstelle. Die TextBox-Steuerelemente haben ihre Text Eigenschaft an den Wert des entsprechenden Datenfelds gebunden, indem sie bidirektionale Datenbindung verwenden.

Das folgende deklarative Markup zeigt die FormViews InsertItemTemplate. Beachten Sie, dass die Bind() Methode hier in der Datenbindungssyntax verwendet wird und dass die Websteuerelemente "Einfügen" und "Abbrechen, Schaltfläche" ihre CommandName Eigenschaften entsprechend festgelegt haben.

<asp:FormView ID="FormView1" runat="server" DataKeyNames="ProductID"
    DataSourceID="ObjectDataSource1" AllowPaging="True">
    <EditItemTemplate>
        ...
    </EditItemTemplate>
    <InsertItemTemplate>
        ProductName:
        <asp:TextBox ID="ProductNameTextBox" runat="server"
           Text="<%# Bind("ProductName") %>">
        </asp:TextBox><br />
        SupplierID:
        <asp:TextBox ID="SupplierIDTextBox" runat="server"
           Text="<%# Bind("SupplierID") %>">
        </asp:TextBox><br />
        CategoryID:
        <asp:TextBox ID="CategoryIDTextBox" runat="server"
           Text="<%# Bind("CategoryID") %>">
        </asp:TextBox><br />
        QuantityPerUnit:
        <asp:TextBox ID="QuantityPerUnitTextBox" runat="server"
           Text="<%# Bind("QuantityPerUnit") %>">
        </asp:TextBox><br />
        UnitPrice:
        <asp:TextBox ID="UnitPriceTextBox" runat="server"
           Text="<%# Bind("UnitPrice") %>">
        </asp:TextBox><br />
        UnitsInStock:
        <asp:TextBox ID="UnitsInStockTextBox" runat="server"
           Text="<%# Bind("UnitsInStock") %>">
        </asp:TextBox><br />
        UnitsOnOrder:
        <asp:TextBox ID="UnitsOnOrderTextBox" runat="server"
           Text="<%# Bind("UnitsOnOrder") %>">
        </asp:TextBox><br />
        ReorderLevel:
        <asp:TextBox ID="ReorderLevelTextBox" runat="server"
           Text="<%# Bind("ReorderLevel") %>">
        </asp:TextBox><br />
        Discontinued:
        <asp:CheckBox ID="DiscontinuedCheckBox" runat="server"
           Checked="<%# Bind("Discontinued") %>" /><br />
        CategoryName:
        <asp:TextBox ID="CategoryNameTextBox" runat="server"
            Text="<%# Bind("CategoryName") %>">
        </asp:TextBox><br />
        SupplierName:
        <asp:TextBox ID="SupplierNameTextBox" runat="server"
           Text="<%# Bind("SupplierName") %>">
        </asp:TextBox><br />
        <asp:LinkButton ID="InsertButton" runat="server"
            CausesValidation="True" CommandName="Insert"
            Text="Insert">
        </asp:LinkButton>
        <asp:LinkButton ID="InsertCancelButton" runat="server"
            CausesValidation="False" CommandName="Cancel"
            Text="Cancel">
        </asp:LinkButton>
    </InsertItemTemplate>
    <ItemTemplate>
        ...
    </ItemTemplate>
</asp:FormView>

Es gibt eine Subtilität bei der automatischen Generation des InsertItemTemplate durch die FormView. Insbesondere werden die TextBox-Websteuerelemente auch für schreibgeschützte Felder erstellt, wie CategoryName und SupplierName. Wie bei der EditItemTemplate müssen wir diese TextBoxes aus dem InsertItemTemplate entfernen.

Abbildung 24 zeigt die FormView in einem Browser beim Hinzufügen eines neuen Produkts, Acme Coffee. Beachten Sie, dass die in ItemTemplate angezeigten Felder SupplierName und CategoryName nicht mehr vorhanden sind, da wir sie soeben entfernt haben. Wenn auf die Schaltfläche "Einfügen" geklickt wird, führt die FormView dieselbe Abfolge von Schritten wie das DetailsView-Steuerelement aus und fügt der Tabelle Products einen neuen Datensatz hinzu. Abbildung 25 zeigt die Details des Acme Coffee-Produkts in der FormView, nachdem es eingefügt wurde.

Die InsertItemTemplate diktiert die Einfügeschnittstelle von FormView

Abbildung 24: Die Einfügeschnittstelle der FormView-Benutzeroberfläche (Klicken Sie, um das Bild in voller Größe anzuzeigen)

Die Details für neues Produkt, Acme Coffee, werden in der FormView angezeigt.

Abbildung 25: Die Details für neues Produkt, Acme Coffee, werden in der FormView angezeigt (Klicken Sie, um das Bild in voller Größe anzuzeigen)

Durch das Trennen der schreibgeschützten, bearbeitenden und einzufügenden Schnittstellen in drei separate Vorlagen ermöglicht die FormView eine bessere Kontrolle über diese Schnittstellen als die DetailsView und GridView.

Hinweis

Wie die DetailsView-Eigenschaft gibt die FormView-Eigenschaft CurrentMode die angezeigte Schnittstelle an, und seine DefaultMode Eigenschaft gibt den Modus an, zu dem die FormView zurückkehrt, nachdem eine Bearbeitung oder ein Einfügen abgeschlossen wurde.

Zusammenfassung

In diesem Lernprogramm haben wir die Grundlagen des Einfügens, Bearbeitens und Löschens von Daten mithilfe von GridView, DetailsView und FormView untersucht. Alle drei Steuerelemente bieten eine gewisse Ebene integrierter Datenänderungsfunktionen, die verwendet werden können, ohne eine einzelne Codezeile in der ASP.NET Seite dank der Datenwebsteuerelemente und der ObjectDataSource zu schreiben. Die einfachen Point- und Click-Techniken führen jedoch zu einer ziemlich anfälligen und unausgereiften Datenänderungs-Benutzeroberfläche. Um eine Überprüfung bereitzustellen, programmgesteuerte Werte einzugeben, Ausnahmen ordnungsgemäß zu behandeln, die Benutzeroberfläche anzupassen usw., müssen wir uns auf eine Vielzahl von Techniken verlassen, die in den nächsten Lernprogrammen behandelt werden.

Glückliche Programmierung!

Zum Autor

Scott Mitchell, Autor von sieben ASP/ASP.NET Büchern und Gründer von 4GuysFromRolla.com, arbeitet seit 1998 mit Microsoft Web Technologies zusammen. Scott arbeitet als unabhängiger Berater, Trainer und Schriftsteller. Sein neuestes Buch ist Sams Teach Yourself ASP.NET 2.0 in 24 Stunden. Er kann bei mitchell@4GuysFromRolla.comerreicht werden.