Freigeben über


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

von Scott Mitchell

PDF herunterladen

In diesem Lernprogramm komprimieren wir den zweiseitigen Master/Detailbericht des vorherigen Lernprogramms in eine einzelne Seite, in der eine Aufzählung der Kategorienamen auf der linken Seite des Bildschirms und die Produkte der ausgewählten Kategorie rechts auf dem Bildschirm angezeigt werden.

Einführung

Im vorherigen Lernprogramm haben wir uns angesehen, wie ein Master-/Detailbericht auf zwei Seiten getrennt wird. Auf der Gestaltungsvorlage haben wir ein Repeater-Steuerelement zum Rendern einer Aufzählung von Kategorien verwendet. Jeder Kategoriename war ein Link, der den Benutzer beim Klicken auf die Detailseite bringen würde, auf der eine zweispaltige DataList diese Produkte anzeigte, die zur ausgewählten Kategorie gehören.

In diesem Lernprogramm komprimieren wir das Lernprogramm auf zwei Seiten in eine einzelne Seite, in der eine Aufzählung von 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 erzeugt und die Produkte der ausgewählten Kategorie an eine zweispaltige DataList auf der rechten Seite des Bildschirms gebunden. Neben der Anzeige jedes Kategorienamens zeigt der Repeater auf der linken Seite, wie viele Produkte für eine bestimmte Kategorie vorhanden sind (siehe Abbildung 1).

Der Name der Kategorie und die Gesamtanzahl der Produkte werden links angezeigt.

Abbildung 1: Der Name der Kategorie und die Gesamtanzahl der Produkte werden auf der linken Seite angezeigt (Klicken Sie, um das Bild in voller Größe anzuzeigen)

Schritt 1: Anzeigen eines Repeaters im linken Bereich des Bildschirms

Für dieses Lernprogramm müssen die Aufzählung der Kategorien links neben den produkten der ausgewählten Kategorie angezeigt werden. Inhalte innerhalb einer Webseite können mithilfe von Standard-HTML-Element-Absatztags, nicht unterbrechenden Leerzeichen, <table> S usw. mithilfe von CSS-Techniken (Cascading Stylesheet) positioniert werden. Alle unsere Lernprogramme haben bisher CSS-Techniken für die Positionierung verwendet. Wenn wir die Navigations-Benutzeroberfläche in unserer Gestaltungsvorlage im Lernprogramm "Gestaltungsvorlagen" und "Websitenavigation" erstellt haben, haben wir absolute Positionierung verwendet, die den genauen Pixeloffset für die Navigationsliste und den Hauptinhalt angibt. Alternativ kann CSS verwendet werden, um ein Element rechts oder links von einer anderen über unverankert zu positionieren. Die Aufzählung der Kategorien kann links neben den Produkten der ausgewählten Kategorie angezeigt werden, indem der Repeater links neben der DataList schwebt.

Öffnen Sie die CategoriesAndProducts.aspx Seite aus dem DataListRepeaterFiltering Ordner, und fügen Sie der Seite einen Repeater und eine DataList hinzu. Legen Sie die Repeater ID auf Categories und die DataList s auf CategoryProducts. Wechseln Sie zur Quellansicht, und platzieren Sie die Steuerelemente "Repeater" und "DataList" in ihren eigenen <div> Elementen. Das heißt, schließen Sie den Repeater zuerst in ein <div> Element ein, und geben Sie dann die DataList direkt hinter dem Repeater in ein eigenes <div> Element ein. Ihr Markup sollte an diesem Punkt ähnlich 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>

Das float: left; erste <div> Element wird links neben dem zweiten Element schwebt. Die width Einstellungen padding-right geben die ersten <div> und width den Abstand zwischen dem Inhalt des <div> Elements und dem rechten Rand an. Weitere Informationen zu unverankerten Elementen in CSS finden Sie im Floatutorial.For more information on floating elements in CSS check out the Floatutorial.

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

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

Dann können wir das <div> durch <div class="FloatLeft">.

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

Der Repeater wird links neben der DataList floated

Abbildung 2: Der Repeater wird links neben 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 zu jedem Kategorienamen auch die Anzahl der Produkte anzeigen, die der Kategorie zugeordnet sind. Um auf diese Informationen zuzugreifen, können wir eine der folgenden Aktionen ausführen:

  • Ermitteln Sie diese Informationen aus der codeBehind-Klasse der ASP.NET Seite. Aufgrund eines bestimmten Vorgangs categoryID können wir die Anzahl der zugeordneten Produkte ermitteln, indem die ProductsBLL Klasse s-Methode GetProductsByCategoryID(categoryID) aufgerufen wird. Diese Methode gibt ein ProductsDataTable Objekt zurück, dessen Count Eigenschaft angibt, wie viele ProductsRow Elemente vorhanden sind. Dies ist die Anzahl der Produkte für das angegebene Objekt categoryID. Wir können einen ItemDataBound Ereignishandler für den Repeater erstellen, der für jede Kategorie, die an den Repeater gebunden ist, die Methode der ProductsBLL Klasse GetProductsByCategoryID(categoryID) aufruft und deren Anzahl in die Ausgabe einschließt.
  • Aktualisieren Sie das CategoriesDataTable in "Typed DataSet" enthaltene Datensatz, um eine NumberOfProducts Spalte einzuschließen. Anschließend können wir die GetCategories() Methode CategoriesDataTable aktualisieren, um diese Informationen einzuschließen oder alternativ die belassene Methode wie folgt zu belassen GetCategories() und eine neue CategoriesDataTable Methode zu erstellen, die aufgerufen wird GetCategoriesAndNumberOfProducts().

Lassen Sie uns beide Techniken untersuchen. Der erste Ansatz ist einfacher zu implementieren, da wir die Datenzugriffsschicht nicht aktualisieren müssen. Dies erfordert jedoch mehr Kommunikation mit der Datenbank. Der Aufruf der ProductsBLL Klassenmethode GetProductsByCategoryID(categoryID) im ItemDataBound Ereignishandler fügt einen zusätzlichen Datenbankaufruf für jede Kategorie hinzu, die im Repeater angezeigt wird. Bei dieser Technik gibt es N +1-Datenbankaufrufe, wobei N die Anzahl der Kategorien ist, die im Repeater angezeigt werden. Mit dem zweiten Ansatz wird die Produktanzahl mit Informationen zu jeder Kategorie aus der CategoriesBLL Klasse GetCategories() (oder GetCategoriesAndNumberOfProducts()) Methode zurückgegeben, wodurch nur eine Reise in die Datenbank entsteht.

Ermitteln der Anzahl der Produkte im ItemDataBound-Ereignishandler

Die Bestimmung der Anzahl der Produkte 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 hinzu, die über das Smarttag "Repeater" benannt CategoriesDataSource ist. Konfigurieren Sie als Nächstes die CategoriesDataSource ObjectDataSource so, dass sie ihre Daten aus der CategoriesBLL Klassenmethode GetCategories() abruft.

Konfigurieren Sie die ObjectDataSource, um die GetCategories()-Methode der CategoriesBLL-Klasse zu verwenden

Abbildung 3: Konfigurieren der ObjectDataSource für die Verwendung der Methode der CategoriesBLL Klasse GetCategories() (Klicken, um das Bild in voller Größe anzuzeigen)

Jedes Element im Categories Repeater muss klickbar sein und bewirkt, dass die CategoryProducts DataList diese Produkte für die ausgewählte Kategorie anzeigt. Dies kann erreicht werden, indem jede Kategorie zu einem Link erstellt wird, der wieder mit derselben Seite (CategoriesAndProducts.aspx) verknüpft wird, aber die Durchlauf der CategoryID Abfragezeichenfolge, ähnlich wie im vorherigen Lernprogramm. Der Vorteil dieses Ansatzes besteht darin, dass eine Seite, die produkte einer bestimmten Kategorie anzeigt, von einer Suchmaschine mit Lesezeichen versehen und indiziert werden kann.

Alternativ können wir jede Kategorie als LinkButton festlegen. Dies ist der Ansatz, den wir für dieses Lernprogramm verwenden werden. Das LinkButton-Element wird im Browser des Benutzers als Link gerendert, führt aber bei Klick zu einem Postback; bei postback muss die DataList s ObjectDataSource aktualisiert werden, um diese Produkte anzuzeigen, die zur ausgewählten Kategorie gehören. Für dieses Lernprogramm ist die Verwendung eines Links sinnvoller als die Verwendung eines LinkButton; Es kann jedoch auch andere Szenarien geben, in denen die Verwendung eines LinkButton-Elements vorteilhafter ist. Der Linkansatz wäre zwar ideal für dieses Beispiel, lassen Sie uns stattdessen die Verwendung von LinkButton erkunden. Wie wir sehen, führt die Verwendung eines LinkButton-Steuerelements einige Herausforderungen ein, die sonst nicht mit einem Link auftreten würden. Daher werden durch die Verwendung eines LinkButton-Elements in diesem Lernprogramm diese Herausforderungen hervorgehoben und Lösungen für diese Szenarien bereitgestellt, in denen wir möglicherweise ein LinkButton anstelle eines Links verwenden möchten.

Hinweis

Sie werden ermutigt, dieses Lernprogramm mithilfe eines HyperLink-Steuerelements oder <a> -Elements 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" /></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 Lernprogramm muss der Repeater seinen Ansichtszustand aktiviert haben (beachten Sie das Auslassen der EnableViewState="False" deklarativen Syntax des Repeaters). In Schritt 3 erstellen wir einen Ereignishandler für das Repeater-Ereignis ItemCommand , in dem die ObjectDataSource-Auflistung SelectParameters von DataList aktualisiert wird. Die Repeater werden jedoch nicht ausgelöst, wenn der Ansichtszustand ItemCommanddeaktiviert ist.

Das LinkButton-Objekt mit dem Eigenschaftswert von besitzt keinen Eigenschaftensatz.The LinkButton with the ID property value of ViewCategory does not have its Text property set. Wenn wir nur den Kategorienamen anzeigen wollten, hätten wir die Text-Eigenschaft deklarativ über die Datenbindungssyntax festgelegt, z. B.:

<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 einen Aufruf der Methode der ProductBLL Klasse GetCategoriesByProductID(categoryID) ausführen und bestimmen, wie viele Datensätze im Ergebnis ProductsDataTablezurückgegeben werden, wie der folgende Code veranschaulicht:

protected void Categories_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
    // Make sure we're working with a data item...
    if (e.Item.ItemType == ListItemType.Item ||
        e.Item.ItemType == ListItemType.AlternatingItem)
    {
        // Reference the CategoriesRow instance bound to this RepeaterItem
        Northwind.CategoriesRow category =
            (Northwind.CategoriesRow) ((System.Data.DataRowView) e.Item.DataItem).Row;
        // Determine how many products are in this category
        NorthwindTableAdapters.ProductsTableAdapter productsAPI =
            new NorthwindTableAdapters.ProductsTableAdapter();
        int productCount =
            productsAPI.GetProductsByCategoryID(category.CategoryID).Count;
        // Reference the ViewCategory LinkButton and set its Text property
        LinkButton ViewCategory = (LinkButton)e.Item.FindControl("ViewCategory");
        ViewCategory.Text =
            string.Format("{0} ({1:N0})", category.CategoryName, productCount);
    }
}

Wir beginnen mit der Sicherstellung, dass wir mit einem Datenelement arbeiten (eines, dessen ItemType Ist oder Item) ist AlternatingItem und dann auf die CategoriesRow Instanz verweist, die gerade an den aktuellen RepeaterItemgebunden wurde. Als Nächstes bestimmen wir die Anzahl der Produkte für diese Kategorie, indem eine Instanz der ProductsBLL Klasse erstellt, die GetCategoriesByProductID(categoryID) Methode aufgerufen und die Anzahl der mit der Count Eigenschaft zurückgegebenen Datensätze bestimmt wird. Schließlich ist das ViewCategory LinkButton-Element in der ItemTemplate Verweise, und seine Text Eigenschaft wird auf CategoryName (NumberOfProductsInCategory) festgelegt, wobei NumberOfProductsInCategory als Zahl mit null Dezimalstellen formatiert ist.

Hinweis

Alternativ könnten wir der codeBehind-Klasse der ASP.NET Seite eine Formatierungsfunktion hinzugefügt haben, die eine Kategorie CategoryName und CategoryID Werte akzeptiert und die CategoryName verkettete Anzahl von Produkten in der Kategorie zurückgibt (wie durch Aufrufen der GetCategoriesByProductID(categoryID) Methode bestimmt). Die Ergebnisse einer solchen Formatierungsfunktion können deklarativ der LinkButton-Text-Eigenschaft zugewiesen werden, die die Notwendigkeit des ItemDataBound Ereignishandlers ersetzt. Weitere Informationen zur Verwendung von Formatierungsfunktionen finden Sie in den Lernprogrammen "Using TemplateFields" im GridView-Steuerelement oder "Formatieren von DataList" und "Repeater Based Upon Data ".

Nachdem Sie diesen Ereignishandler hinzugefügt haben, nehmen Sie sich einen Moment Zeit, um die Seite über einen Browser zu testen. Beachten Sie, wie jede Kategorie in einer Aufzählung aufgeführt wird, wobei der Name der Kategorie und die Anzahl der Produkte angezeigt werden, die der Kategorie zugeordnet sind (siehe Abbildung 4).

Jeder Kategoriename und die Anzahl der Produkte werden angezeigt.

Abbildung 4: Jeder Kategoriename und die Anzahl der Produkte werden angezeigt (Zum Anzeigen des Bilds mit voller Größe klicken)

Aktualisieren derCategoriesDataTableUndCategoriesTableAdaptereinschließen der Anzahl der Produkte für jede Kategorie

Anstatt die Anzahl der Produkte für jede Kategorie zu ermitteln, die an den Repeater gebunden ist, können wir diesen Prozess optimieren, indem wir die CategoriesDataTable Datenzugriffsebene anpassen, CategoriesTableAdapter um diese Informationen nativ einzuschließen. Um dies zu erreichen, müssen wir eine neue Spalte hinzufügen, um CategoriesDataTable die Anzahl der zugehörigen Produkte zu enthalten. Um einer DataTable eine neue Spalte hinzuzufügen, öffnen Sie das typierte 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 der CategoriesDataTable Spalte eine neue Spalte hinzu (siehe Abbildung 5).

Hinzufügen einer neuen Spalte zur CategoriesDataSource

Abbildung 5: Hinzufügen einer neuen Spalte zum CategoriesDataSource Bild in voller Größe (Klicken, um das Bild in voller Größe anzuzeigen)

Dadurch wird eine neue Spalte namens Column1hinzugefügt, die Sie ändern können, indem Sie einfach einen anderen Namen eingeben. Benennen Sie diese neue Spalte in 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 Spalte DataType in System.StringSystem.Int32 die Eigenschaft, und legen Sie sie ReadOnly wie in Abbildung 6 dargestellt auf Truefest.

Festlegen der Datentyp- und ReadOnly-Eigenschaften der neuen Spalte

Abbildung 6: Festlegen der DataType Eigenschaften ReadOnly der neuen Spalte

Obwohl die CategoriesDataTable Spalte jetzt über eine NumberOfProducts Spalte verfügt, wird der Wert von keiner der entsprechenden TableAdapter-Abfragen festgelegt. Wir können die GetCategories() Methode aktualisieren, um diese Informationen zurückzugeben, wenn diese Informationen jedes Mal zurückgegeben werden sollen, wenn Kategorieinformationen abgerufen werden. Wenn wir jedoch nur die Anzahl der zugehörigen Produkte für die Kategorien in seltenen Fällen abrufen müssen (z. B. nur für dieses Lernprogramm), können wir dies belassen GetCategories() und eine neue Methode erstellen, die diese Informationen zurückgibt. Lassen Sie uns diesen letzteren Ansatz verwenden, indem wir eine neue Methode mit dem Namen GetCategoriesAndNumberOfProducts()erstellen.

Um diese neue GetCategoriesAndNumberOfProducts() Methode hinzuzufügen, klicken Sie mit der rechten Maustaste auf die CategoriesTableAdapter neue Abfrage, und wählen Sie "Neue Abfrage" aus. Dadurch wird der TableAdapter-Abfragekonfigurations-Assistent angezeigt, den wir in früheren Lernprogrammen 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, 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, um das Bild in voller Größe anzuzeigen)

Auf dem nächsten Assistentenbildschirm werden wir aufgefordert, die zu verwendende Abfrage zu verwenden. Verwenden Sie die folgende CategoryID Anweisung, um die einzelnen Kategorien CategoryNameDescriptionund SELECT Felder 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 (Zum Anzeigen des Bilds mit voller Größe klicken)

Beachten Sie, dass die Unterabfrage, die die Anzahl der Produkte berechnet, die der Kategorie zugeordnet sind, als Alias verwendet NumberOfProductswird. Diese Namensüberstimmung bewirkt, dass der von dieser Unterabfrage zurückgegebene Wert der CategoriesDataTable Spalte "s NumberOfProducts " zugeordnet wird.

Nach der Eingabe dieser Abfrage besteht der letzte Schritt darin, den Namen für die neue Methode auszuwählen. Verwenden Sie FillWithNumberOfProducts bzw GetCategoriesAndNumberOfProducts . für die Füllung einer DataTable und zurückgeben Sie ein DataTable-Muster.

Benennen der neuen TableAdapter-Methoden FillWithNumberOfProducts und GetCategoriesAndNumberOfProducts

Abbildung 10: Benennen der Methoden FillWithNumberOfProducts des neuen TableAdapter-Elements und GetCategoriesAndNumberOfProducts (Klicken Sie, 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 der Präsentationsebene über eine separate Geschäftslogikebene an die DAL weitergeleitet werden, müssen wir der GetCategoriesAndNumberOfProducts Klasse eine entsprechende CategoriesBLL Methode hinzufügen:

[System.ComponentModel.DataObjectMethodAttribute
    (System.ComponentModel.DataObjectMethodType.Select, false)]
public Northwind.CategoriesDataTable GetCategoriesAndNumberOfProducts()
{
    return Adapter.GetCategoriesAndNumberOfProducts();
}

Nachdem dal und BLL abgeschlossen sind, sind wir bereit, diese Daten an den Categories Repeater zu binden!CategoriesAndProducts.aspx Wenn Sie bereits eine ObjectDataSource für den Repeater aus dem Abschnitt "Bestimmen der Anzahl der Produkte" im ItemDataBound Abschnitt "Ereignishandler" erstellt haben, löschen Sie diese ObjectDataSource, und entfernen Sie die Eigenschaftseinstellung des DataSourceID Repeaters. Entfernen Sie auch das Repeater-Ereignis ItemDataBound aus dem Ereignishandler, indem Sie die Handles Categories.OnItemDataBound Syntax in der ASP.NET CodeBehind-Klasse entfernen.

Fügen Sie mit dem Repeater im ursprünglichen Zustand eine neue ObjectDataSource hinzu, die über das Smarttag "Repeater" benannt CategoriesDataSource ist. Konfigurieren Sie objectDataSource so, dass sie die CategoriesBLL Klasse verwendet, aber statt sie verwenden zu GetCategories() lassen, verwenden Sie sie GetCategoriesAndNumberOfProducts() stattdessen (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, um das Bild in voller Größe anzuzeigen)

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

<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 Produkte der ausgewählten Kategorie

An diesem Punkt zeigt der Categories Repeater die Liste der Kategorien zusammen mit der Anzahl der Produkte in jeder Kategorie an. Der Repeater verwendet ein LinkButton für jede Kategorie, die, wenn sie geklickt wird, zu einem Postback führt, an dem wir diese Produkte für die ausgewählte Kategorie in der DataList anzeigen müssen.The Repeater uses a LinkButton for each category that when clicked, when clicked, a postback, at which point we need to display those products for the selected category in the CategoryProducts DataList.

Eine Herausforderung, die uns gegenübersteht, besteht darin, dass die DataList nur diese Produkte für die ausgewählte Kategorie anzeigt. Im Master/Detail Using a Selectable Master GridView with a Details DetailsView tutorial we saw how to build a GridView whose rows could be selected, with the selected row s details being displayed in a DetailsView on the same page. Die GridView s ObjectDataSource hat Informationen zu allen Produkten mit der ProductsBLL s-Methode GetProducts() zurückgegeben, während die DetailsView s ObjectDataSource Informationen über das ausgewählte Produkt mithilfe der GetProductsByProductID(productID) Methode abgerufen hat. 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 der Herausforderungen, die beim Verwenden von LinkButton in einem Repeater auftreten. Wenn wir stattdessen einen Hyperlink zum Übergeben der CategoryID Abfragezeichenfolge verwendet haben, konnten wir dieses QueryString-Feld als Quelle für den Wert des Parameters verwenden.

Bevor wir uns jedoch gedanken über den Mangel an SelectedValue Eigenschaft für den Repeater machen, lassen Sie uns zuerst die DataList an eine ObjectDataSource binden und deren ItemTemplateEigenschaft angeben.

Wählen Sie im Smarttag von DataList ein neues ObjectDataSource-Element hinzu CategoryProductsDataSource , und konfigurieren Sie sie für die Verwendung der ProductsBLL Klassenmethode GetProductsByCategoryID(categoryID) . Da die DataList in diesem Lernprogramm eine schreibgeschützte Schnittstelle bietet, können Sie die Dropdownlisten in den Registerkarten INSERT, UPDATE und DELETE auf (Keine) festlegen.

Konfigurieren Sie die ObjectDataSource so, dass sie die Methode GetProductsByCategoryID(categoryID) der Klasse ProductsBLL verwendet

Abbildung 12: Konfigurieren der ObjectDataSource für die Verwendung ProductsBLL der Klassenmethode GetProductsByCategoryID(categoryID) (Klicken, um das Bild in voller Größe anzuzeigen)

Da die GetProductsByCategoryID(categoryID) Methode einen Eingabeparameter erwartet (categoryID), ermöglicht uns der Assistent "Datenquelle konfigurieren" die Angabe der Quelle des Parameters. Wenn die Kategorien in einer GridView oder einer DataList aufgeführt wurden, haben wir die Dropdownliste "Parameterquelle" auf "Control" und "ControlID" auf das ID Datenwebsteuerelement festgelegt. Da der Repeater jedoch keine SelectedValue Eigenschaft aufweist, kann er nicht als Parameterquelle verwendet werden. Wenn Sie überprüfen, werden Sie feststellen, dass die Dropdownliste "ControlID" nur ein Steuerelement ID``CategoryProductsenthält, das ID der DataList entspricht.

Legen Sie vorerst die Dropdownliste "Parameterquelle" auf "Keine" fest. Dieser Parameterwert wird programmgesteuert zugewiesen, wenn im Repeater auf ein LinkButton-Element der Kategorie geklickt wird.

Keine Parameterquelle für den categoryID-Parameter angeben

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

Nach Abschluss des Assistenten zum Konfigurieren von Datenquellen generiert Visual Studio die DataList s ItemTemplateautomatisch. Ersetzen Sie diese Standardeinstellung ItemTemplate durch die Vorlage, die wir im vorherigen Lernprogramm verwendet haben. Legen Sie außerdem die DataList s-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 wird der CategoryProductsDataSource Parameter ObjectDataSource categoryID nie festgelegt, sodass beim Anzeigen der Seite keine Produkte angezeigt werden. Was wir tun müssen, ist, dass dieser Parameterwert basierend auf der CategoryID angeklickten Kategorie im Repeater festgelegt ist. Dies führt zu zwei Herausforderungen: Wie bestimmen wir zunächst, wann auf ein LinkButton-Element in den Repeater-Steuerelementen ItemTemplate geklickt wurde, und zweitens, wie können wir die CategoryID entsprechende Kategorie bestimmen, auf deren LinkButton geklickt wurde?

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

Wenn ein Command Ereignis aus einer Vorlage im Repeater ausgelöst wird, wird das Repeater-Ereignis ItemCommand ausgelöst und die CommandName Werte CommandArgument des angeklickten LinkButton (oder Button oder ImageButton) übergeben. Um zu ermitteln, wann auf ein Kategorie-LinkButton-Element im Repeater geklickt wurde, müssen wir folgende Schritte ausführen:

  1. Legen Sie die CommandName Eigenschaft von LinkButton in den Repeater-Steuerelementen ItemTemplate auf einen bestimmten Wert fest (ich habe ListProducts verwendet). Durch Festlegen dieses CommandName Werts wird das LinkButton-Ereignis Command ausgelöst, wenn auf das LinkButton-Element geklickt wird.
  2. Legen Sie die LinkButton s-Eigenschaft CommandArgument auf den Wert der aktuellen Elemente fest CategoryID.
  3. Erstellen Sie einen Ereignishandler für das Repeater-Ereignis ItemCommand . Legen Sie im Ereignishandler den CategoryProductsDataSource Parameter ObjectDataSource auf CategoryID den Wert des übergebenen CommandArgumentObjekts fest.

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

<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>

Jedes Mal, wenn ein ItemCommand Ereignishandler erstellt wird, ist es umsichtig, immer zuerst den eingehenden CommandName Wert zu überprüfen, da jedesCommand Ereignis, das von einem Button -, LinkButton- oder ImageButton-Element innerhalb des Repeaters ausgelöst wird, das ItemCommand Ereignis ausgelöst wird. Obwohl wir derzeit nur über ein solches LinkButton verfügen, könnten 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 mit Ihrer programmgesteuerten Logik fortfahren, wenn sie mit dem erwarteten Wert übereinstimmt.

Nachdem sichergestellt wurde, dass der übergebene CommandName Wert ListProducts entspricht, weist der Ereignishandler dann dem Wert des übergebenen CategoryProductsDataSourceObjekts den CategoryID Parameter ObjectDataSource CommandArgument zu. Durch diese Änderung an den ObjectDataSource-Objekten SelectParameters wird die DataList automatisch mit der Datenquelle verknüpft, wobei die Produkte für die neu ausgewählte Kategorie angezeigt werden.

protected void Categories_ItemCommand(object source, RepeaterCommandEventArgs e)
{
    // If it's the "ListProducts" command that has been issued...
    if (string.Compare(e.CommandName, "ListProducts", true) == 0)
    {
        // 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();
    }
}

Mit diesen Ergänzungen ist unser Lernprogramm 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 noch keine Kategorie ausgewählt werden muss, werden keine Produkte angezeigt. Wenn Sie auf eine Kategorie klicken, z. B. "Produzieren", 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 (Zum Anzeigen des Bilds mit voller Größe klicken)

Klicken auf die Kategorie

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

Zusammenfassung

Wie wir in diesem Lernprogramm und dem vorherigen gesehen haben, können Master-/Detailberichte auf zwei Seiten verteilt oder auf einer Seite konsolidiert werden. Das Anzeigen eines Master-/Detailberichts auf einer einzelnen Seite führt jedoch einige Herausforderungen zum Layout des Master- und Detaildatenblatts auf der Seite ein. Im Master/Detail Using a Selectable Master GridView with a Details DetailsView tutorial we had the details records appear above the master records; in this tutorial we used CSS techniques to have the master records float to the left of the details.

Zusammen mit der Anzeige von Master-/Detailberichten hatten wir auch die Möglichkeit, die Anzahl der produkte abzurufen, die jeder Kategorie zugeordnet sind, sowie wie serverseitige Logik ausgeführt wird, wenn ein LinkButton (oder Button oder ImageButton) in einem Repeater klickt.

Dieses Lernprogramm schließt unsere Untersuchung von Master-/Detailberichten mit der DataList und dem Repeater ab. In unseren nächsten Lernprogrammen wird veranschaulicht, wie Sie dem DataList-Steuerelement Bearbeitungs- und Löschfunktionen hinzufügen.

Glückliche Programmierung!

Weitere nützliche Informationen

Weitere Informationen zu den in diesem Lernprogramm erläuterten 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 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.

Besonderer Dank an

Diese Lernprogrammreihe wurde von vielen hilfreichen Prüfern überprüft. Lead Reviewer für dieses Lernprogramm war Zack Jones. Möchten Sie meine bevorstehenden MSDN-Artikel überprüfen? Wenn ja, schicken Sie mir eine Nachricht an mitchell@4GuysFromRolla.com.