Freigeben über


Master-/Detailbericht mit einer Aufzählung der Masterdatensätze und einem DataList-Steuerelement für die Details (VB)

von Scott Mitchell

PDF herunterladen

In diesem Tutorial komprimieren wir den zweiseitigen master/Detailbericht des vorherigen Tutorials auf eine einzelne Seite, in der eine Aufzählungsliste mit Kategorienamen auf der linken Seite des Bildschirms und die Produkte der ausgewählten Kategorie auf der rechten Seite des Bildschirms angezeigt werden.

Einführung

Im vorherigen Tutorial haben wir uns mit der Trennung eines master-/Detailberichts auf zwei Seiten befasst. Auf der Seite master haben wir ein Repeater-Steuerelement verwendet, um eine Aufzählung von Kategorien zu rendern. Jeder Kategoriename war ein Link, der den Benutzer beim Klicken zur Detailseite führte, auf der eine zweispaltige DataList die Produkte anzeigte, die zur ausgewählten Kategorie gehören.

In diesem Tutorial komprimieren wir das zweiseitige Tutorial in eine einzelne Seite, wobei eine Aufzählungsliste mit Kategorienamen auf der linken Seite des Bildschirms angezeigt wird, wobei jeder Kategoriename als LinkButton gerendert wird. Durch Klicken auf einen der Kategorienamen LinkButtons wird ein Postback ausgelöst und die produkte der ausgewählten Kategorie an eine zweispaltige DataList auf der rechten Seite des Bildschirms gebunden. Neben dem Namen der einzelnen Kategorien zeigt der Repeater auf der linken Seite an, wie viele Produkte insgesamt für eine bestimmte Kategorie vorhanden sind (siehe Abbildung 1).

Der Name der Kategorie und die Gesamtanzahl der Produkte werden auf der linken Seite angezeigt.

Abbildung 1: Der Name der Kategorie und die Gesamtanzahl der Produkte werden auf der linken Seite angezeigt (Klicken Sie, um das vollständige Bild anzuzeigen)

Schritt 1: Anzeigen eines Repeaters im linken Bereich des Bildschirms

Für dieses Tutorial muss links neben den Produkten der ausgewählten Kategorie die Aufzählungsliste der Kategorien angezeigt werden. Inhalte auf einer Webseite können mithilfe von Standard-HTML-Element-Absatztags, nicht brechenden Leerzeichen, <table> s usw. oder mithilfe von CSS-Techniken (Cascading Stylesheet) positioniert werden. Alle unsere Tutorials haben bisher CSS-Techniken für die Positionierung verwendet. Als wir die Navigationsbenutzeroberfläche in unserer master Seite im Tutorial Gestaltungsseiten und Websitenavigation erstellt haben, haben wir die absolute Positionierung verwendet, um den präzisen Pixeloffset für die Navigationsliste und den Standard Inhalt anzugeben. Alternativ kann CSS verwendet werden, um ein Element rechts oder links von einem anderen durch Floating zu positionieren. Wir können die Aufzählungsliste der Kategorien links neben den ausgewählten Produkten der Kategorie anzeigen lassen, indem der Repeater links neben der DataList angezeigt wird.

Öffnen Sie die CategoriesAndProducts.aspx Seite aus dem DataListRepeaterFiltering Ordner, und fügen Sie der Seite einen Repeater und eine DataList hinzu. Legen Sie den Repeater s ID auf Categories und die DataList s auf fest CategoryProducts. Wechseln Sie zur Quellansicht, und fügen Sie die Steuerelemente Repeater und DataList in ihre eigenen <div> Elemente ein. Das heißt, schließen Sie zuerst den Repeater in ein <div> -Element und dann die DataList in ein eigenes <div> Element direkt nach dem Repeater ein. Ihr Markup sollte an dieser Stelle wie folgt aussehen:

<div>
    <asp:Repeater ID="Categories" runat="server">
    </asp:Repeater>
</div>
<div>
    <asp:DataList ID="CategoryProducts" runat="server">
    </asp:DataList>
</div>

Um den Repeater links neben der DataList zu verschieben, müssen wir das float CSS-Formatattribut wie folgt verwenden:

<div>
    Repeater
</div>
<div>
    DataList
</div>

Die float: left; schwebt das erste <div> Element links vom zweiten Element. Die width Einstellungen und padding-right geben die ersten <div> s width an und wie viel Abstand zwischen dem Inhalt des <div> Elements und dem rechten Rand hinzugefügt wird. Weitere Informationen zu schwebenden Elementen in CSS finden Sie unter Floatutorial.

Anstatt die Stileinstellung direkt über das Attribut des ersten <p> Elements anzugeben style , erstellen sie stattdessen eine neue CSS-Klasse mit Styles.css dem Namen FloatLeft:

.FloatLeft
{
    float: left;
    width: 33%;
    padding-right: 10px;
}

Dann können sie durch <div class="FloatLeft">ersetzen<div>.

Nachdem Sie die CSS-Klasse hinzugefügt und das Markup auf der CategoriesAndProducts.aspx Seite konfiguriert haben, wechseln Sie zum Designer. Sie sollten den Repeater links neben der DataList sehen (obwohl beide im Moment nur als graue Felder angezeigt werden, da wir ihre Datenquellen oder Vorlagen noch nicht konfigurieren müssen).

Der Repeater wird links von der DataList angezeigt.

Abbildung 2: Der Repeater wird links von der DataList angezeigt (Klicken Sie hier, um das bild in voller Größe anzuzeigen)

Schritt 2: Bestimmen der Anzahl der Produkte für jede Kategorie

Nachdem das umgebende Markup für Repeater und DataList abgeschlossen ist, können wir die Kategoriedaten an das Repeater-Steuerelement binden. Wie jedoch die Aufzählung der Kategorien in Abbildung 1 zeigt, müssen wir zusätzlich zum Namen jeder Kategorie auch die Anzahl der produkte anzeigen, die der Kategorie zugeordnet sind. Um auf diese Informationen zuzugreifen, können wir entweder:

  • Ermitteln Sie diese Informationen aus der CodeBehind-Klasse der ASP.NET Seite. Bei einem bestimmten Wert categoryID können wir die Anzahl der zugeordneten Produkte bestimmen, indem wir die ProductsBLL Methode der Klasse s GetProductsByCategoryID(categoryID) aufrufen. Diese Methode gibt ein ProductsDataTable -Objekt zurück, dessen Count Eigenschaft angibt, wie viele ProductsRow s vorhanden sind. Dies ist die Anzahl der Produkte für das angegebene categoryID. Wir können einen ItemDataBound Ereignishandler für den Repeater erstellen, der für jede kategorie, die an den Repeater gebunden ist, die ProductsBLL Klasse s-Methode GetProductsByCategoryID(categoryID) aufruft und deren Anzahl in die Ausgabe einschließt.
  • Aktualisieren Sie den CategoriesDataTable im Typisierten DataSet, um eine NumberOfProducts Spalte einzuschließen. Wir können dann die GetCategories() -Methode in CategoriesDataTable aktualisieren, um diese Informationen einzuschließen, oder alternativ unverändert lassen GetCategories() und eine neue CategoriesDataTable Methode mit dem Namen GetCategoriesAndNumberOfProducts()erstellen.

Lassen Sie uns beide Techniken untersuchen. Der erste Ansatz ist einfacher zu implementieren, da die Datenzugriffsebene nicht aktualisiert werden muss. Dies erfordert jedoch mehr Kommunikation mit der Datenbank. Der Aufruf der ProductsBLL Klasse s-Methode GetProductsByCategoryID(categoryID) im ItemDataBound Ereignishandler fügt einen zusätzlichen Datenbankaufruf für jede kategorie hinzu, die im Repeater angezeigt wird. Bei diesem Verfahren gibt es N + 1 Datenbankaufrufe, wobei N die Anzahl der im Repeater angezeigten Kategorien ist. Beim zweiten Ansatz wird die Produktanzahl mit Informationen zu jeder Kategorie aus der Methode der CategoriesBLL Klasse s GetCategories() (oder GetCategoriesAndNumberOfProducts()) zurückgegeben, was zu nur einem Trip zur Datenbank führt.

Ermitteln der Anzahl von Produkten im ItemDataBound-Ereignishandler

Die Bestimmung der Anzahl von Produkten für jede Kategorie im Repeater-Ereignishandler ItemDataBound erfordert keine Änderungen an unserer vorhandenen Datenzugriffsebene. Alle Änderungen können direkt auf der CategoriesAndProducts.aspx Seite vorgenommen werden. Fügen Sie zunächst eine neue ObjectDataSource mit dem Namen über CategoriesDataSource das Smarttag des Repeaters hinzu. Konfigurieren Sie als Nächstes die CategoriesDataSource ObjectDataSource so, dass sie ihre Daten aus der Methode der CategoriesBLL Klasse s abruft GetCategories() .

Konfigurieren der ObjectDataSource für die Verwendung der GetCategories()-Methode der CategoriesBLL-Klasse

Abbildung 3: Konfigurieren der ObjectDataSource für die Verwendung der Methode der CategoriesBLLGetCategories() Klasse (Klicken Sie hier, um das bild in voller Größe anzuzeigen)

Jedes Element im Categories Repeater muss angeklickt werden können, und wenn darauf geklickt wird, wird die CategoryProducts DataList dazu führen, dass diese Produkte für die ausgewählte Kategorie angezeigt werden. Dies kann erreicht werden, indem Sie jede Kategorie zu einem Hyperlink machen und eine Verknüpfung mit derselben Seite (CategoriesAndProducts.aspx) herstellen, aber die CategoryID Abfragezeichenfolge durchgibt, ähnlich wie im vorherigen Tutorial. Der Vorteil dieses Ansatzes besteht darin, dass eine Seite, die Produkte einer bestimmten Kategorie anzeigt, von einer Suchmaschine als Lesezeichen und indiziert werden kann.

Alternativ können wir jede Kategorie als LinkButton festlegen. Dies ist der Ansatz, den wir für dieses Tutorial verwenden. Der LinkButton wird im Browser des Benutzers als Link gerendert, löst jedoch beim Klicken ein Postback aus. beim Postback muss die DataList-ObjektDataSource aktualisiert werden, um die Produkte anzuzeigen, die zur ausgewählten Kategorie gehören. In diesem Tutorial ist die Verwendung eines Links sinnvoller als die Verwendung eines LinkButton. es kann jedoch auch andere Szenarien geben, in denen die Verwendung eines LinkButton-Steuerelements vorteilhafter ist. Während der Hyperlinkansatz für dieses Beispiel ideal wäre, lassen Sie uns stattdessen die Verwendung von LinkButton untersuchen. Wie wir sehen werden, bringt die Verwendung eines LinkButton einige Herausforderungen mit sich, die andernfalls bei einem Link nicht auftreten würden. Daher werden durch die Verwendung eines LinkButton in diesem Tutorial diese Herausforderungen hervorgehoben und Lösungen für die Szenarien bereitgestellt, in denen wir möglicherweise einen LinkButton anstelle eines Hyperlinks verwenden möchten.

Hinweis

Es wird empfohlen, dieses Tutorial mit einem HyperLink-Steuerelement oder <a> -Element anstelle von LinkButton zu wiederholen.

Das folgende Markup zeigt die deklarative Syntax für den Repeater und die ObjectDataSource. Beachten Sie, dass die Vorlagen des Repeaters eine Aufzählung mit jedem Element als LinkButton rendern:

<asp:Repeater ID="Categories" runat="server" DataSourceID="CategoriesDataSource">
    <HeaderTemplate>
        <ul>
    </HeaderTemplate>
    <ItemTemplate>
        <li><asp:LinkButton runat="server" ID="ViewCategory"></asp:LinkButton></li>
    </ItemTemplate>
    <FooterTemplate>
        </ul>
    </FooterTemplate>
</asp:Repeater>
<asp:ObjectDataSource ID="CategoriesDataSource" runat="server"
    OldValuesParameterFormatString="original_{0}"
    SelectMethod="GetCategories" TypeName="CategoriesBLL">
</asp:ObjectDataSource>

Hinweis

Für dieses Tutorial muss der Ansichtszustand für den Repeater aktiviert sein (beachten Sie die Auslassung von der EnableViewState="False" deklarativen Syntax des Repeaters). In Schritt 3 erstellen wir einen Ereignishandler für das Repeater-Ereignis ItemCommand , in dem wir die DataList s ObjectDataSource-Auflistung SelectParameters aktualisieren. Der Repeater wird jedoch nicht ausgelöst, wenn der Ansichtszustand ItemCommanddeaktiviert ist.

Für linkButton mit dem ID Eigenschaftswert von ViewCategory ist seine Text Eigenschaft nicht festgelegt. Wenn wir nur den Kategorienamen anzeigen wollten, hätten wir die Text-Eigenschaft deklarativ über die Datenbindungssyntax wie folgt festgelegt:

<asp:LinkButton runat="server" ID="ViewCategory"
    Text='<%# Eval("CategoryName") %>' />

Wir möchten jedoch sowohl den Namen der Kategorie als auch die Anzahl der Produkte anzeigen, die zu dieser Kategorie gehören. Diese Informationen können aus dem Repeater-Ereignishandler ItemDataBound abgerufen werden, indem Sie die Methode der ProductBLL Klasse s GetCategoriesByProductID(categoryID) aufrufen und bestimmen, wie viele Datensätze im resultierenden ProductsDataTablezurückgegeben werden, wie der folgende Code veranschaulicht:

Protected Sub Categories_ItemDataBound(sender As Object, e As RepeaterItemEventArgs)
    ' Make sure we're working with a data item...
    If e.Item.ItemType = ListItemType.Item OrElse _
        e.Item.ItemType = ListItemType.AlternatingItem Then
        ' Reference the CategoriesRow instance bound to this RepeaterItem
        Dim category As Northwind.CategoriesRow = _
            CType(CType(e.Item.DataItem, System.Data.DataRowView).Row, _
                Northwind.CategoriesRow)
        ' Determine how many products are in this category
        Dim productsAPI As New NorthwindTableAdapters.ProductsTableAdapter
        Dim productCount As Integer = _
            productsAPI.GetProductsByCategoryID(category.CategoryID).Count
        ' Reference the ViewCategory LinkButton and set its Text property
        Dim ViewCategory As LinkButton = _
            CType(e.Item.FindControl("ViewCategory"), LinkButton)
        ViewCategory.Text = _
            String.Format("{0} ({1:N0})", category.CategoryName, productCount)
    End If
End Sub

Zunächst stellen wir sicher, dass wir mit einem Datenelement arbeiten (eines, dessen ItemType oder istItem) AlternatingItemund dann auf die CategoriesRow instance verweisen, die gerade an das aktuelle RepeaterItemgebunden wurde. Als Nächstes bestimmen wir die Anzahl der Produkte für diese Kategorie, indem wir eine instance der -Klasse erstellen, ihre ProductsBLLGetCategoriesByProductID(categoryID) Methode aufrufen und die Anzahl der mit der Count -Eigenschaft zurückgegebenen Datensätze ermitteln. Schließlich ist der ViewCategory LinkButton in der ItemTemplate Verweise, und seine Text Eigenschaft ist auf CategoryName (NumberOfProductsInCategory) festgelegt, wobei NumberOfProductsInCategory als Zahl mit null Dezimalstellen formatiert ist.

Hinweis

Alternativ hätten wir der CodeBehind-Klasse der ASP.NET Seite eine Formatierungsfunktion hinzugefügt, die eine Kategorie s CategoryName und Werte akzeptiert und CategoryID die CategoryName mit der Anzahl der Produkte in der Kategorie verkettet zurückgibt (wie durch aufrufen der GetCategoriesByProductID(categoryID) -Methode ermittelt). Die Ergebnisse einer solchen Formatierungsfunktion könnten deklarativ der Text-Eigenschaft von LinkButton zugewiesen werden, wodurch die Notwendigkeit des ItemDataBound Ereignishandlers ersetzt wird. Weitere Informationen zur Verwendung von Formatierungsfunktionen finden Sie in den Tutorials Verwenden von TemplateFields im GridView-Steuerelement oder Formatieren von DataList und Repeater basierend auf Daten .

Nehmen Sie sich nach dem Hinzufügen dieses Ereignishandlers einen Moment Zeit, um die Seite über einen Browser zu testen. Beachten Sie, wie jede Kategorie in einer Aufzählungsliste aufgeführt wird, in der der Name der Kategorie und die Anzahl der der Kategorie zugeordneten Produkte angezeigt werden (siehe Abbildung 4).

Jeder Kategoriename und die Anzahl der Produkte werden angezeigt.

Abbildung 4: Name und Anzahl der Produkte jeder Kategorie werden angezeigt (Klicken Sie hier, um das bild in voller Größe anzuzeigen)

Aktualisieren vonCategoriesDataTableundCategoriesTableAdapter, um die Anzahl der Produkte für jede Kategorie einzuschließen

Anstatt die Anzahl der Produkte für jede Kategorie zu bestimmen, da sie an den Repeater gebunden ist, können wir diesen Prozess optimieren, indem wir und CategoriesDataTableCategoriesTableAdapter in der Datenzugriffsebene so anpassen, dass diese Informationen nativ eingeschlossen werden. Um dies zu erreichen, müssen wir eine neue Spalte hinzufügen, um CategoriesDataTable die Anzahl der zugeordneten Produkte zu enthalten. Um einer DataTable eine neue Spalte hinzuzufügen, öffnen Sie das Typisierte DataSet (App_Code\DAL\Northwind.xsd), klicken Sie mit der rechten Maustaste auf die zu ändernde DataTable, und wählen Sie Hinzufügen/Spalte aus. Fügen Sie dem CategoriesDataTable eine neue Spalte hinzu (siehe Abbildung 5).

Hinzufügen einer neuen Spalte zur CategoriesDataSource

Abbildung 5: Hinzufügen einer neuen Spalte zu (Klicken Sie hier, um dasCategoriesDataSource Bild in voller Größe anzuzeigen)

Dadurch wird eine neue Spalte mit dem Namen Column1hinzugefügt, die Sie ändern können, indem Sie einfach einen anderen Namen eingeben. Benennen Sie diese neue Spalte in um NumberOfProducts. Als Nächstes müssen wir die Eigenschaften dieser Spalte konfigurieren. Klicken Sie auf die neue Spalte, und wechseln Sie zum Eigenschaftenfenster. Ändern Sie die Eigenschaft der DataType Spalte von in System.String , System.Int32 und legen Sie die ReadOnly -Eigenschaft auf Truefest, wie in Abbildung 6 dargestellt.

Festlegen der Eigenschaften DataType und ReadOnly der neuen Spalte

Abbildung 6: Festlegen der DataType Eigenschaften und ReadOnly der neuen Spalte

Während der CategoriesDataTable jetzt über eine NumberOfProducts Spalte verfügt, wird sein Wert von keiner der entsprechenden TableAdapter-Abfragen festgelegt. Wir können die GetCategories() -Methode aktualisieren, um diese Informationen zurückzugeben, wenn diese Informationen bei jedem Abruf von Kategorieinformationen zurückgegeben werden sollen. Wenn wir jedoch nur in seltenen Fällen (z. B. nur für dieses Tutorial) die Anzahl der zugeordneten Produkte für die Kategorien abrufen müssen, können wir unverändert bleiben GetCategories() und eine neue Methode erstellen, die diese Informationen zurückgibt. Verwenden wir diesen letztgenannten Ansatz, um eine neue Methode namens zu GetCategoriesAndNumberOfProducts()erstellen.

Um diese neue GetCategoriesAndNumberOfProducts() Methode hinzuzufügen, klicken Sie mit der rechten Maustaste auf die CategoriesTableAdapter , und wählen Sie Neue Abfrage aus. Dadurch wird der TableAdapter-Abfragekonfigurations-Assistent angezeigt, den wir in den vorherigen Tutorials mehrfach verwendet haben. Starten Sie für diese Methode den Assistenten, indem Sie angeben, dass die Abfrage eine Ad-hoc-SQL-Anweisung verwendet, die Zeilen zurückgibt.

Erstellen der -Methode mithilfe einer Ad-hoc-SQL-Anweisung

Abbildung 7: Erstellen der Methode mithilfe einer Ad-hoc-SQL-Anweisung (Klicken Sie hier, um das Bild in voller Größe anzuzeigen)

Die SQL-Anweisung gibt Zeilen zurück.

Abbildung 8: Die SQL-Anweisung gibt Zeilen zurück (Klicken Sie hier, um das Bild in voller Größe anzuzeigen)

Auf dem nächsten Assistentenbildschirm werden wir aufgefordert, die zu verwendende Abfrage einzugeben. Verwenden Sie die folgende SELECT Anweisung, um die Felder der einzelnen Kategorien CategoryID, CategoryNameund Description zusammen mit der Anzahl der produkte zurückzugeben, die der Kategorie zugeordnet sind:

SELECT CategoryID, CategoryName, Description,
       (SELECT COUNT(*) FROM Products p WHERE p.CategoryID = c.CategoryID)
            as NumberOfProducts
FROM Categories c

Angeben der zu verwendenden Abfrage

Abbildung 9: Angeben der zu verwendenden Abfrage (Klicken Sie hier, um das Bild in voller Größe anzuzeigen)

Beachten Sie, dass die Unterabfrage, die die Anzahl der produkte berechnet, die der Kategorie zugeordnet sind, als NumberOfProductsAlias verwendet wird. Diese Namensübereinstimmung bewirkt, dass der von dieser Unterabfrage zurückgegebene Wert der CategoriesDataTable Spalte s NumberOfProducts zugeordnet wird.

Nachdem Sie diese Abfrage eingegeben haben, müssen Sie im letzten Schritt den Namen für die neue Methode auswählen. Verwenden Sie FillWithNumberOfProducts und GetCategoriesAndNumberOfProducts für die Muster Eine DataTable ausfüllen bzw. Zurückgeben einer DataTable.

Nennen Sie die New TableAdapter-Methoden FillWithNumberOfProducts und GetCategoriesAndNumberOfProducts.

Abbildung 10: Benennen Sie die neuen TableAdapter-Methoden FillWithNumberOfProducts und GetCategoriesAndNumberOfProducts (Klicken Sie hier, um das Bild in voller Größe anzuzeigen)

An diesem Punkt wurde die Datenzugriffsebene erweitert, um die Anzahl der Produkte pro Kategorie einzuschließen. Da alle Aufrufe an die DAL über eine separate Geschäftslogikebene weitergeleitet werden, müssen wir der CategoriesBLL -Klasse eine entsprechende GetCategoriesAndNumberOfProducts Methode hinzufügen:

<System.ComponentModel.DataObjectMethodAttribute _
    (System.ComponentModel.DataObjectMethodType.Select, False)> _
Public Function GetCategoriesAndNumberOfProducts() As Northwind.CategoriesDataTable
    Return Adapter.GetCategoriesAndNumberOfProducts()
End Function

Wenn DAL und BLL abgeschlossen sind, sind wir bereit, diese Daten an den Categories Repeater in CategoriesAndProducts.aspxzu binden. Wenn Sie bereits eine ObjectDataSource für den Repeater aus dem Abschnitt Bestimmen der Anzahl von Produkten im ItemDataBound Ereignishandler erstellt haben, löschen Sie diese ObjectDataSource, und entfernen Sie die Einstellung der Repeater-Eigenschaft DataSourceID . Trennen Sie auch das Repeater s-Ereignis ItemDataBound aus dem Ereignishandler, indem Sie die Handles Categories.OnItemDataBound Syntax in der ASP.NET CodeBehind-Klasse entfernen.

Wenn sich der Repeater wieder im ursprünglichen Zustand befindet, fügen Sie über das Smarttag des Repeaters eine neue ObjectDataSource mit dem Namen CategoriesDataSource hinzu. Konfigurieren Sie die ObjectDataSource so, dass die CategoriesBLL -Klasse verwendet wird, aber anstatt die GetCategories() -Methode zu verwenden, sollten Sie sie stattdessen verwenden GetCategoriesAndNumberOfProducts() (siehe Abbildung 11).

Konfigurieren der ObjectDataSource für die Verwendung der GetCategoriesAndNumberOfProducts-Methode

Abbildung 11: Konfigurieren der ObjectDataSource für die Verwendung der GetCategoriesAndNumberOfProducts -Methode (Klicken Sie hier, um das Bild in voller Größe anzuzeigen)

Aktualisieren Sie als Nächstes, ItemTemplate sodass die LinkButton-Eigenschaft deklarativ Text mithilfe der Datenbindungssyntax zugewiesen wird und sowohl die CategoryName Datenfelder als NumberOfProducts auch enthält. Das vollständige deklarative Markup für den Repeater und die CategoriesDataSource ObjectDataSource folgt:

<asp:Repeater ID="Categories" runat="server" DataSourceID="CategoriesDataSource">
    <HeaderTemplate>
        <ul>
    </HeaderTemplate>
    <ItemTemplate>
        <li><asp:LinkButton runat="server" ID="ViewCategory"
                Text='<%# String.Format("{0} ({1:N0})", _
                    Eval("CategoryName"), Eval("NumberOfProducts")) %>' />
        </li>
    </ItemTemplate>
    <FooterTemplate>
        </ul>
    </FooterTemplate>
</asp:Repeater>
<asp:ObjectDataSource ID="CategoriesDataSource" runat="server"
    OldValuesParameterFormatString="original_{0}"
    SelectMethod="GetCategoriesAndNumberOfProducts" TypeName="CategoriesBLL">
</asp:ObjectDataSource>

Die Ausgabe, die durch Aktualisieren der DAL gerendert wird, um eine NumberOfProducts Spalte einzuschließen, entspricht der Verwendung des ItemDataBound Ereignishandleransatzes (siehe Abbildung 4, um einen Screenshot des Repeaters mit den Kategorienamen und der Anzahl der Produkte anzuzeigen).

Schritt 3: Anzeigen der ausgewählten Produkte der Kategorie

An diesem Punkt haben wir den Categories Repeater, der die Liste der Kategorien zusammen mit der Anzahl der Produkte in jeder Kategorie anzeigt. Der Repeater verwendet ein LinkButton-Element für jede Kategorie, die beim Klicken ein Postback verursacht. An diesem Punkt müssen wir diese Produkte für die ausgewählte Kategorie in der CategoryProducts DataList anzeigen.

Eine Herausforderung besteht darin, wie die DataList nur die Produkte für die ausgewählte Kategorie anzeigt. Im Tutorial Master/Detail Using a Selectable Master GridView with a DetailsView (Details DetailsView ) wurde erläutert, wie Sie ein GridView-Objekt erstellen, dessen Zeilen ausgewählt werden können, wobei die Details der ausgewählten Zeilen in einer Detailansicht auf derselben Seite angezeigt werden. Die GridView s ObjectDataSource hat mithilfe der ProductsBLL s-Methode GetProducts() Informationen zu allen Produkten zurückgegeben, während die ObjectDataSource von DetailsView Mithilfe der GetProductsByProductID(productID) -Methode Informationen zum ausgewählten Produkt abrufte. Der productID Parameterwert wurde deklarativ bereitgestellt, indem er dem Wert der GridView-Eigenschaft SelectedValue zugeordnet wurde. Leider verfügt der Repeater nicht über eine SelectedValue -Eigenschaft und kann nicht als Parameterquelle dienen.

Hinweis

Dies ist eine dieser Herausforderungen, die bei der Verwendung von LinkButton in einem Repeater auftreten. Hätten wir stattdessen einen Link verwendet, um die CategoryID abfragezeichenfolge zu übergeben, könnten wir dieses QueryString-Feld als Quelle für den Wert des Parameters verwenden.

Bevor wir uns jedoch Gedanken über das Fehlen einer SelectedValue Eigenschaft für den Repeater machen, sollten wir zuerst die DataList an eine ObjectDataSource binden und deren ItemTemplateangeben.

Wählen Sie im Smarttag DataList das Hinzufügen einer neuen ObjectDataSource mit dem Namen CategoryProductsDataSource aus, und konfigurieren Sie sie für die Verwendung der s-Methode GetProductsByCategoryID(categoryID) der ProductsBLL Klasse. Da dataList in diesem Tutorial eine schreibgeschützte Schnittstelle bietet, können Sie die Dropdownlisten in den Registerkarten INSERT, UPDATE und DELETE auf (Keine) festlegen.

Konfigurieren der ObjectDataSource für die Verwendung von ProductsBLL-Klasse s GetProductsByCategoryID(categoryID)-Methode

Abbildung 12: Konfigurieren der ObjectDataSource für die Verwendung ProductsBLL der Klasse s-Methode (Klicken Sie hier, um ein Bild in voller Größe anzuzeigen)GetProductsByCategoryID(categoryID)

Da die GetProductsByCategoryID(categoryID) -Methode einen Eingabeparameter (categoryID) erwartet, können wir mit dem Assistenten Datenquelle konfigurieren die Quelle des Parameters angeben. Wenn die Kategorien in einem GridView- oder DataList-Objekt aufgeführt wurden, würden wir die Dropdownliste Parameterquelle auf Control und die ControlID auf die ID des Datenwebsteuerelements festlegen. Da dem Repeater jedoch keine SelectedValue Eigenschaft fehlt, kann er nicht als Parameterquelle verwendet werden. Wenn Sie dies überprüfen, stellen Sie fest, dass die Dropdownliste ControlID nur ein Steuerelement ID``CategoryProductsenthält, das der ID DataList.

Legen Sie vorerst die Dropdownliste Parameterquelle auf Keine fest. Wir weisen diesen Parameterwert programmgesteuert zu, wenn im Repeater auf eine Kategorie LinkButton geklickt wird.

Geben Sie keine Parameterquelle für den categoryID-Parameter an.

Abbildung 13: Keine Parameterquelle für den categoryID Parameter angeben (Klicken Sie hier, um das Bild in voller Größe anzuzeigen)

Nach Abschluss des Assistenten zum Konfigurieren von Datenquellen generiert Visual Studio automatisch die DataList-Datei ItemTemplate. Ersetzen Sie diese Standardeinstellung ItemTemplate durch die Vorlage, die wir im vorherigen Tutorial verwendet haben. Legen Sie außerdem die DataList-Eigenschaft RepeatColumns auf 2 fest. Nachdem Sie diese Änderungen vorgenommen haben, sollte das deklarative Markup für Ihre DataList und die zugehörige ObjectDataSource wie folgt aussehen:

<asp:DataList ID="CategoryProducts" runat="server" DataKeyField="ProductID"
    DataSourceID="CategoryProductsDataSource" RepeatColumns="2"
    EnableViewState="False">
    <ItemTemplate>
        <h5><%# Eval("ProductName") %></h5>
        <p>
            Supplied by <%# Eval("SupplierName") %><br />
            <%# Eval("UnitPrice", "{0:C}") %>
        </p>
    </ItemTemplate>
</asp:DataList>
<asp:ObjectDataSource ID="CategoryProductsDataSource"
    OldValuesParameterFormatString="original_{0}"  runat="server"
    SelectMethod="GetProductsByCategoryID" TypeName="ProductsBLL">
    <SelectParameters>
        <asp:Parameter Name="categoryID" Type="Int32" />
    </SelectParameters>
</asp:ObjectDataSource>

Derzeit ist der CategoryProductsDataSource Parameter ObjectDataSource categoryID nie festgelegt, sodass beim Anzeigen der Seite keine Produkte angezeigt werden. Wir müssen diesen Parameterwert basierend auf der CategoryID der angeklickten Kategorie im Repeater festlegen. Dies führt zu zwei Herausforderungen: Erstens, wie bestimmen wir, wann auf ein LinkButton in den Repeater-Instanzen geklickt wurde, und zweitens ItemTemplate , wie können wir die CategoryID der entsprechenden Kategorie ermitteln, auf deren LinkButton geklickt wurde?

Das LinkButton-Steuerelement wie die Steuerelemente Button und ImageButton verfügt über ein Click -Ereignis und ein Command -Ereignis. Das Click Ereignis ist so konzipiert, dass einfach darauf hingewiesen wird, dass auf linkButton geklickt wurde. Manchmal müssen wir jedoch nicht nur feststellen, dass auf linkButton geklickt wurde, auch einige zusätzliche Informationen an den Ereignishandler übergeben. Wenn dies der Fall ist, können die LinkButton-Eigenschaften CommandName und CommandArgument diese zusätzlichen Informationen zugewiesen werden. Wenn dann auf linkButton geklickt wird, wird das Command -Ereignis (anstelle des Click -Ereignisses) ausgelöst, und dem Ereignishandler werden die Werte der CommandName Eigenschaften und CommandArgument übergeben.

Wenn ein Command Ereignis innerhalb einer Vorlage im Repeater ausgelöst wird, wird das Repeater-EreignisItemCommand ausgelöst und die CommandName Werte und CommandArgument des geklickten LinkButton (oder Button oder ImageButton) übergeben. Um zu ermitteln, wann auf eine Kategorie LinkButton im Repeater geklickt wurde, müssen wir daher wie folgt vorgehen:

  1. Legen Sie die CommandName Eigenschaft von LinkButton in den Repeater auf ItemTemplate einen Wert fest (Ich habe ListProducts verwendet). Wenn Sie diesen CommandName Wert festlegen, wird das LinkButton-Ereignis Command ausgelöst, wenn auf linkButton geklickt wird.
  2. Legen Sie die LinkButton-Eigenschaft CommandArgument auf den Wert des aktuellen Elements s CategoryIDfest.
  3. Erstellen Sie einen Ereignishandler für das Repeater s-Ereignis ItemCommand . Legen Sie im Ereignishandler den CategoryProductsDataSource ObjectDataSource-Parameter auf CategoryID den Wert des übergebenen CommandArgumentfest.

Das folgende ItemTemplate Markup für den Categories Repeater implementiert die Schritte 1 und 2. Beachten Sie, wie dem CommandArgument Wert das Datenelement s CategoryID mithilfe der Datenbindungssyntax zugewiesen wird:

<ItemTemplate>
    <li>
        <asp:LinkButton CommandName="ListProducts"  runat="server"
            CommandArgument='<%# Eval("CategoryID") %>' ID="ViewCategory"
            Text='<%# string.Format("{0} ({1:N0})", _
                Eval("CategoryName"), Eval("NumberOfProducts")) %>'>
        </asp:LinkButton>
    </li>
</ItemTemplate>

Beim Erstellen eines ItemCommand Ereignishandlers ist es ratsam, immer zuerst den eingehenden CommandName Wert zu überprüfen, da jedes Ereignis, dasCommand von einem Button-, LinkButton- oder ImageButton-Element innerhalb des Repeaters ausgelöst wird, das ItemCommand Ereignis auslöst. Obwohl derzeit nur ein LinkButton vorhanden ist, können wir (oder ein anderer Entwickler in unserem Team) dem Repeater zusätzliche Schaltflächen-Websteuerelemente hinzufügen, die beim Klicken auf denselben ItemCommand Ereignishandler ausgelöst werden. Daher ist es am besten, immer sicherzustellen, dass Sie die CommandName Eigenschaft überprüfen und nur dann mit Ihrer programmgesteuerten Logik fortfahren, wenn sie dem erwarteten Wert entspricht.

Nachdem sichergestellt wurde, dass der übergebene CommandName Wert gleich ListProducts ist, weist der Ereignishandler den CategoryProductsDataSource ObjectDataSource-Parameter CategoryID dem Wert des übergebenen CommandArgumentzu. Diese Änderung an den ObjectDataSources SelectParameters bewirkt automatisch, dass sich die DataList erneut an die Datenquelle bindet und die Produkte für die neu ausgewählte Kategorie anzeigt.

Protected Sub Categories_ItemCommand(source As Object, e As RepeaterCommandEventArgs) _
    Handles Categories.ItemCommand
    ' If it's the "ListProducts" command that has been issued...
    If String.Compare(e.CommandName, "ListProducts", True) = 0 Then
        ' Set the CategoryProductsDataSource ObjectDataSource's CategoryID parameter
        ' to the CategoryID of the category that was just clicked (e.CommandArgument)...
        CategoryProductsDataSource.SelectParameters("CategoryID").DefaultValue = _
            e.CommandArgument.ToString()
    End If
End Sub

Mit diesen Ergänzungen ist unser Tutorial abgeschlossen! Nehmen Sie sich einen Moment Zeit, um es in einem Browser zu testen. Abbildung 14 zeigt den Bildschirm beim ersten Besuch der Seite. Da eine Kategorie noch ausgewählt wurde, werden keine Produkte angezeigt. Wenn Sie auf eine Kategorie wie "Produzieren" klicken, werden diese Produkte in der Kategorie Produkt in einer zweispaltigen Ansicht angezeigt (siehe Abbildung 15).

Beim ersten Besuch der Seite werden keine Produkte angezeigt.

Abbildung 14: Beim ersten Besuch der Seite werden keine Produkte angezeigt (Klicken Sie hier, um das Bild in voller Größe anzuzeigen)

Klicken Sie auf die Kategorie

Abbildung 15: Klicken auf die Kategorie "Produzieren" Listen übereinstimmende Produkte rechts (Klicken Sie hier, um das Bild in voller Größe anzuzeigen)

Zusammenfassung

Wie in diesem Tutorial und im vorherigen Tutorial gezeigt, können master-/Detailberichte auf zwei Seiten verteilt oder auf einer seite konsolidiert werden. Das Anzeigen eines master-/Detailberichts auf einer einzelnen Seite stellt jedoch einige Herausforderungen hinsichtlich des optimalen Layouts der master- und Detaildatensätze auf der Seite dar. Im Tutorial Master/Detail Using a Selectable Master GridView with a Details DetailsView (Master/Detail Using a Selectable Master GridView with a Details DetailsView) wurden die Detaildatensätze über den master Datensätzen angezeigt. In diesem Tutorial haben wir CSS-Techniken verwendet, damit die master Datensätze links neben den Details angezeigt werden.

Neben der Anzeige von master/Detailberichten hatten wir auch die Möglichkeit, die Anzahl der produkte abzurufen, die jeder Kategorie zugeordnet sind, und wie serverseitige Logik ausgeführt wird, wenn in einem Repeater auf ein LinkButton (oder Button oder ImageButton) geklickt wird.

In diesem Tutorial wird die Untersuchung von master-/Detailberichten mit DataList und Repeater abgeschlossen. In unseren nächsten Tutorials wird veranschaulicht, wie Sie dem DataList-Steuerelement Bearbeitungs- und Löschfunktionen hinzufügen.

Viel Spaß beim Programmieren!

Weitere Informationen

Weitere Informationen zu den in diesem Tutorial behandelten Themen finden Sie in den folgenden Ressourcen:

Zum Autor

Scott Mitchell, Autor von sieben ASP/ASP.NET-Büchern und Gründer von 4GuysFromRolla.com, arbeitet seit 1998 mit Microsoft-Webtechnologien. Scott arbeitet als unabhängiger Berater, Trainer und Autor. Sein neuestes Buch ist Sams Teach Yourself ASP.NET 2.0 in 24 Hours. Er kann unter mitchell@4GuysFromRolla.comoder über seinen Blog erreicht werden, der unter http://ScottOnWriting.NETzu finden ist.

Besonderer Dank an

Diese Tutorialreihe wurde von vielen hilfreichen Prüfern überprüft. Leitender Prüfer für dieses Tutorial war Zack Jones. Möchten Sie meine bevorstehenden MSDN-Artikel lesen? Wenn dies der Fall ist, legen Sie eine Zeile unter abmitchell@4GuysFromRolla.com.