Filtro master/dettaglio tra due pagine usando un controllo ripetitore e DataList (C#)

di Scott Mitchell

Scarica il PDF

In questa esercitazione viene illustrato come separare un report master/dettaglio tra due pagine. Nella pagina "master" viene usato un controllo Repeater per eseguire il rendering di un elenco di categorie che, quando si fa clic, l'utente verrà visualizzato nella pagina "dettagli" in cui un datalist a due colonne mostra tali prodotti appartenenti alla categoria selezionata.

Introduzione

Nell'esercitazione precedente è stato illustrato come visualizzare i report master/dettagli in una singola pagina Web usando DropDownLists per visualizzare i record "master" e un Oggetto DataList per visualizzare i "dettagli". Un altro modello comune usato per i report master/dettagli consiste nell'avere i record master in una pagina Web e i dettagli su un altro. Nell'esercitazione precedente filtro master/dettaglio su due pagine , è stato esaminato questo modello usando GridView per visualizzare tutti i fornitori nel sistema. GridView include un oggetto HyperLinkField, che viene eseguito il rendering come collegamento a una seconda pagina, passando lungo l'oggetto SupplierID nella querystring. La seconda pagina usa GridView per elencare i prodotti forniti dal fornitore selezionato.

Tali report master/dettaglio a due pagine possono essere eseguiti anche usando i controlli DataList e Repeater. L'unica differenza è che né DataList né Repeater forniscono il supporto per il controllo HyperLinkField. È invece necessario aggiungere un controllo Web HyperLink o un elemento HTML di ancoraggio (<a>) all'interno del ItemTemplatecontrollo . La proprietà HyperLink NavigateUrl o l'attributo dell'ancoraggio href possono quindi essere personalizzati usando approcci dichiarativi o programmatici.

In questa esercitazione verrà illustrato un esempio che elenca le categorie in un elenco puntato in una sola pagina usando un controllo Ripetitore. Ogni elemento di elenco includerà il nome e la descrizione della categoria, con il nome della categoria visualizzato come collegamento a una seconda pagina. Facendo clic su questo collegamento, l'utente verrà eseguito il whisking nella seconda pagina, in cui un Oggetto DataList mostrerà i prodotti che appartengono alla categoria selezionata.

Passaggio 1: Visualizzazione delle categorie in un elenco puntato

Il primo passaggio della creazione di un report master/dettaglio consiste nel visualizzare i record "master". Pertanto, la prima attività consiste nel visualizzare le categorie nella pagina "master". Aprire la CategoryListMaster.aspx pagina nella DataListRepeaterFiltering cartella, aggiungere un controllo Repeater e, dallo smart tag, scegliere di aggiungere un nuovo OggettoDataSource. Configurare il nuovo OggettoDataSource in modo che acceda ai dati dal CategoriesBLL metodo della GetCategories classe (vedere la figura 1).

Configurare ObjectDataSource per usare il metodo GetCategories della classe CategoriesBLL

Figura 1: Configurare ObjectDataSource per usare il metodo della GetCategories classe (fare clic per visualizzare l'immagineCategoriesBLL full-size)

Definire quindi i modelli di Repeater in modo che visualizzino ogni nome di categoria e descrizione come elemento in un elenco puntato. Non è ancora necessario avere ogni collegamento di categoria alla pagina dei dettagli. Di seguito viene illustrato il markup dichiarativo per Repeater e ObjectDataSource:

<asp:Repeater ID="Repeater1" runat="server" DataSourceID="ObjectDataSource1"
    EnableViewState="False">
    <HeaderTemplate>
        <ul>
    </HeaderTemplate>
 
    <ItemTemplate>
        <li><%# Eval("CategoryName") %> - <%# Eval("Description") %></li>
    </ItemTemplate>
 
    <FooterTemplate>
        </ul>
    </FooterTemplate>
</asp:Repeater>
 
<asp:ObjectDataSource ID="ObjectDataSource1" runat="server"
    OldValuesParameterFormatString="original_{0}"
    SelectMethod="GetCategories" TypeName="CategoriesBLL">
</asp:ObjectDataSource>

Con questo markup completato, è necessario un momento per visualizzare lo stato di avanzamento tramite un browser. Come illustrato nella figura 2, il ripetitore esegue il rendering come elenco puntato che mostra il nome e la descrizione di ogni categoria.

Ogni categoria viene visualizzata come elemento elenco puntato

Figura 2: Ogni categoria viene visualizzata come elemento elenco puntato (fare clic per visualizzare l'immagine a dimensioni complete)

Per consentire a un utente di visualizzare le informazioni "dettagli" per una determinata categoria, è necessario aggiungere un collegamento a ogni elemento elenco puntato che, quando viene fatto clic, porterà l'utente alla seconda pagina (ProductsForCategoryDetails.aspx). Questa seconda pagina visualizzerà quindi i prodotti per la categoria selezionata usando un oggetto DataList. Per determinare la categoria il cui collegamento è stato fatto clic, è necessario passare la categoria CategoryID selezionata alla seconda pagina tramite un meccanismo. Il modo più semplice e semplice per trasferire i dati scalari da una pagina a un altro consiste nell'esecuzione della querystring, ovvero l'opzione che verrà usata in questa esercitazione. In particolare, la ProductsForCategoryDetails.aspx pagina prevede che il valore selezionato categoryID venga passato tramite un campo querystring denominato CategoryID. Ad esempio, per visualizzare i prodotti per la categoria Bevande, con un CategoryID valore pari a 1, un utente visiterebbe ProductsForCategoryDetails.aspx?CategoryID=1.

Per creare un collegamento ipertestuale per ogni elemento elenco puntato nel ripetitore, è necessario aggiungere un controllo Web HyperLink o un elemento di ancoraggio HTML (<a>) all'oggetto ItemTemplate. Negli scenari in cui viene visualizzato lo stesso collegamento ipertestuale per ogni riga, entrambi gli approcci saranno sufficienti. Per i ripetitori, preferisco usare l'elemento di ancoraggio. Per usare l'elemento di ancoraggio, aggiornare l'elemento ItemTemplate di Repeater a:

<li>
    <a href='ProductsForCategoryDetails.aspx?CategoryID=<%# Eval("CategoryID") %>'>
        <%# Eval("CategoryName") %>
    </a> - <%# Eval("Description") %>
</li>

Si noti che l'elemento CategoryID può essere inserito direttamente all'interno dell'attributo dell'elemento di ancoraggio; tuttavia, a tale scopo, essere certi di delimitare il href valore dell'attributo con apostrofi (e virgolette note) poiché il Eval metodo all'interno href dell'attributo href delimita la stringa ("CategoryID") con virgolette. In alternativa, è possibile usare un controllo Web HyperLink:

<li>
    <asp:HyperLink runat="server" Text='<%# Eval("CategoryName") %>'
        NavigateUrl='<%# "ProductsForCategoryDetails.aspx?CategoryID=" &
            Eval("CategoryID") %>'>
    </asp:HyperLink>
    - <%# Eval("Description") %>
</li>

Si noti come la parte statica dell'URL , ProductsForCategoryDetails.aspx?CategoryID aggiunta al risultato direttamente Eval("CategoryID") all'interno della sintassi di associazione dati usando la concatenazione stringa.

Un vantaggio dell'uso del controllo HyperLink è che può essere accessibile a livello di codice dal gestore eventi ItemDataBound di Repeater, se necessario. Ad esempio, è possibile visualizzare il nome della categoria come testo anziché come collegamento per le categorie senza prodotti associati. Tale controllo potrebbe essere eseguito a livello di codice nel ItemDataBound gestore eventi. Per le categorie senza prodotti associati, la proprietà HyperLink NavigateUrl potrebbe essere impostata su una stringa vuota, causando così il rendering di tale nome di categoria come testo normale anziché come collegamento. Per altre informazioni sulla formattazione del contenuto di DataList e Ripetitore in base ai dati , vedere l'esercitazione Formattazione del contenuto di DataList e Repeater in base alla logica programmatica tramite il ItemDataBound gestore eventi.

Se si segue, è possibile usare l'elemento di ancoraggio o l'approccio di controllo HyperLink nella pagina. Indipendentemente dall'approccio, quando si visualizza la pagina tramite un browser ogni nome di categoria deve essere eseguito il rendering come collegamento a ProductsForCategoryDetails.aspx, passando il valore applicabile CategoryID (vedere la figura 3).

I nomi delle categorie ora sono collegati a ProductsForCategoryDetails.aspx

Figura 3: I nomi delle categorie a cui si collega (fare clic per visualizzare l'immagine a dimensioni complete)ProductsForCategoryDetails.aspx

Passaggio 3: Elencare i prodotti appartenenti alla categoria selezionata

Con il completamento della pagina, siamo pronti a richiamare l'attenzione sull'implementazione della CategoryListMaster.aspx pagina ProductsForCategoryDetails.aspx"dettagli", . Aprire questa pagina, trascinare un oggetto DataList dalla casella degli strumenti nella Designer e impostarne la ID proprietà su ProductsInCategory. Successivamente, dallo smart tag di DataList scegliere di aggiungere un nuovo OggettoDataSource alla pagina, assegnando la denominazione ProductsInCategoryDataSourcea . Configurarla in modo che chiami il ProductsBLL metodo della GetProductsByCategoryID(categoryID) classe; impostare gli elenchi a discesa nelle schede INSERT, UPDATE e DELETE su (Nessuno).

Configurare ObjectDataSource per usare il metodo GetProductsByCategoryID(categoryID) della classe ProductsBLL

Figura 4: Configurare ObjectDataSource per usare il metodo della GetProductsByCategoryID(categoryID) classe (fare clic per visualizzare l'immagineProductsBLL full-size)

Poiché il metodo accetta un parametro di input (categoryID), la GetProductsByCategoryID(categoryID) procedura guidata Scegli origine dati offre l'opportunità di specificare l'origine del parametro. Impostare l'origine del parametro su QueryString usando QueryStringField CategoryID.

Usare querystring Field CategoryID come origine del parametro

Figura 5: Usare il campo CategoryID Querystring come origine del parametro (fare clic per visualizzare l'immagine full-size)

Come illustrato nelle esercitazioni precedenti, dopo aver completato la procedura guidata Scegli origine dati, Visual Studio crea automaticamente un ItemTemplate oggetto per DataList che elenca ogni nome e valore del campo dati. Sostituire questo modello con uno che elenca solo il nome, il fornitore e il prezzo del prodotto. Impostare anche la proprietà di RepeatColumns DataList su 2. Dopo queste modifiche, il markup dichiarativo di DataList e ObjectDataSource dovrebbe essere simile al seguente:

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

Per visualizzare questa pagina in azione, iniziare dalla pagina. Fare clic su un collegamento nell'elenco CategoryListMaster.aspx puntato categorie. In questo modo si porterà a ProductsForCategoryDetails.aspx, passando lungo la CategoryID querystring. ObjectDataSource ProductsInCategoryDataSource in ProductsForCategoryDetails.aspx otterrà quindi solo i prodotti per la categoria specificata e li visualizzerà in DataList, che esegue il rendering di due prodotti per riga. La figura 6 mostra uno screenshot di ProductsForCategoryDetails.aspx quando si visualizzano le bevande.

Le bevande vengono visualizzate, due per riga

Figura 6: Le bevande vengono visualizzate, due per riga (fare clic per visualizzare l'immagine a dimensioni complete)

Passaggio 4: Visualizzazione delle informazioni sulle categorie in ProductsForCategoryDetails.aspx

Quando un utente fa clic su una categoria in CategoryListMaster.aspx, vengono presi in ProductsForCategoryDetails.aspx e visualizzati i prodotti che appartengono alla categoria selezionata. Tuttavia, in ProductsForCategoryDetails.aspx non ci sono segnali visivi come a quale categoria è stata selezionata. Un utente che voleva fare clic su Bevande, ma accidentalmente fatto clic su Condimenti, non ha modo di capire il loro errore dopo aver raggiunto ProductsForCategoryDetails.aspx. Per alleviare questo potenziale problema, è possibile visualizzare informazioni sulla categoria selezionata , il nome e la descrizione, nella parte superiore della ProductsForCategoryDetails.aspx pagina.

A tale scopo, aggiungere un controllo FormView sopra il controllo Ripetitore in ProductsForCategoryDetails.aspx. Aggiungere quindi un nuovo OggettoDataSource alla pagina dallo smart tag di FormView denominato CategoryDataSource e configurarlo per usare il CategoriesBLL metodo della GetCategoryByCategoryID(categoryID) classe.

Accedere alle informazioni sulla categoria tramite il metodo GetCategoryByCategoryID(categoryID) della classe CategoriesBLL

Figura 7: Accedere alle informazioni sulla categoria tramite il CategoriesBLL metodo della GetCategoryByCategoryID(categoryID) classe (fare clic per visualizzare l'immagine full-size)

Come per ProductsInCategoryDataSource ObjectDataSource aggiunto al passaggio 3, la CategoryDataSourceprocedura guidata Configura origine dati richiede un'origine per il GetCategoryByCategoryID(categoryID) parametro di input del metodo. Usare le stesse impostazioni di prima, impostando l'origine del parametro su QueryString e il valore QueryStringField su CategoryID (fare riferimento alla figura 5).

Dopo aver completato la procedura guidata, Visual Studio crea automaticamente un ItemTemplateoggetto , EditItemTemplatee InsertItemTemplate per FormView. Poiché si fornisce un'interfaccia di sola lettura, è possibile rimuovere e EditItemTemplateInsertItemTemplate. Inoltre, è possibile personalizzare l'oggetto FormView.ItemTemplate Dopo aver rimosso i modelli superflui e personalizzando ItemTemplate, il markup dichiarativo di FormView e ObjectDataSource dovrebbe essere simile al seguente:

<asp:FormView ID="FormView1" runat="server" DataKeyNames="CategoryID"
    DataSourceID="CategoryDataSource" EnableViewState="False" Width="100%">
    <ItemTemplate>
        <h3>
            <asp:Label ID="CategoryNameLabel" runat="server"
                Text='<%# Bind("CategoryName") %>' />
        </h3>
        <p>
            <asp:Label ID="DescriptionLabel" runat="server"
                Text='<%# Bind("Description") %>' />
        </p>
    </ItemTemplate>
</asp:FormView>
 
<asp:ObjectDataSource ID="CategoryDataSource" runat="server"
    OldValuesParameterFormatString="original_{0}"
    SelectMethod="GetCategoryByCategoryID" TypeName="CategoriesBLL">
    <SelectParameters>
        <asp:QueryStringParameter Name="categoryID" Type="Int32"
            QueryStringField="CategoryID" />
    </SelectParameters>
</asp:ObjectDataSource>

La figura 8 mostra una schermata durante la visualizzazione di questa pagina tramite un browser.

Nota

Oltre a FormView, ho aggiunto anche un controllo HyperLink sopra FormView che restituirà l'utente all'elenco di categorie (CategoryListMaster.aspx). È possibile posizionare questo collegamento altrove o o ometterlo completamente.

Le informazioni sulla categoria sono ora visualizzate nella parte superiore della pagina

Figura 8: Le informazioni sulle categorie sono ora visualizzate nella parte superiore della pagina (fare clic per visualizzare l'immagine a dimensioni complete)

Passaggio 5: Visualizzazione di un messaggio se nessun prodotto appartiene alla categoria selezionata

La CategoryListMaster.aspx pagina elenca tutte le categorie nel sistema, indipendentemente dal fatto che siano presenti prodotti associati. Se un utente fa clic su una categoria senza prodotti associati, il rendering di DataList in ProductsForCategoryDetails.aspx non verrà eseguito, perché l'origine dati non includerà alcun elemento. Come illustrato nelle esercitazioni precedenti, GridView fornisce una EmptyDataText proprietà che può essere usata per specificare un messaggio di testo da visualizzare se non sono presenti record nell'origine dati. Sfortunatamente, né DataList né Repeater hanno una proprietà di questo tipo.

Per visualizzare un messaggio che informa l'utente che non sono presenti prodotti corrispondenti per la categoria selezionata, è necessario aggiungere un controllo Etichetta alla pagina la cui Text proprietà è assegnata al messaggio da visualizzare nel caso in cui non siano presenti prodotti corrispondenti. È quindi necessario impostare la relativa Visible proprietà a livello di codice in base al fatto che DataList contenga o meno elementi.

A tale scopo, iniziare aggiungendo un'etichetta sotto l'oggetto DataList. Impostare la relativa ID proprietà su NoProductsMessage e la relativa Text proprietà su "There are no products for the selected category..." (Nessun prodotto per la categoria selezionata...) Successivamente, è necessario impostare a livello di codice la proprietà di Visible questa etichetta in base al fatto che i dati siano stati associati o meno a ProductsInCategory DataList. Questa assegnazione deve essere eseguita dopo che i dati sono stati associati a DataList. Per GridView, DetailsView e FormView, è possibile creare un gestore eventi per l'evento del controllo, che viene generato dopo il completamento dell'associazione DataBound dati. Tuttavia, né DataList né Repeater dispone di un DataBound evento disponibile.

Per questo particolare esempio è possibile assegnare la proprietà dell'etichetta Visible nel Page_Load gestore eventi, poiché i dati saranno stati assegnati a DataList prima dell'evento della Load pagina. Tuttavia, questo approccio non funziona nel caso generale, perché i dati di ObjectDataSource potrebbero essere associati a DataList più avanti nel ciclo di vita della pagina. Ad esempio, se i dati visualizzati sono basati sul valore in un altro controllo, ad esempio quando si visualizza un report master/dettaglio utilizzando un oggetto DropDownList per contenere i record "master", i dati potrebbero non essere rimbalzati al controllo Web dati fino alla PreRender fase del ciclo di vita della pagina.

Una soluzione che funzionerà per tutti i casi consiste nell'assegnare la Visible proprietà a False nel gestore eventi (o ItemCreated) di ItemDataBound DataList quando si associa un tipo di elemento di Item o AlternatingItem. In questo caso si sa che nell'origine dati è presente almeno un elemento di dati e quindi può nascondere l'etichetta NoProductsMessage . Oltre a questo gestore eventi, è necessario anche un gestore eventi per l'evento di DataBinding DataList, in cui si inizializza la proprietà dell'etichetta Visible su True. Poiché l'evento DataBinding viene generato prima degli ItemDataBound eventi, la proprietà dell'etichetta Visible verrà inizialmente impostata su True; se sono presenti elementi di dati, tuttavia, verrà impostata su False. Il codice seguente implementa questa logica:

protected void ProductsInCategory_DataBinding(object sender, EventArgs e)
{
    // Show the Label
    NoProductsMessage.Visible = true;
}
 
protected void ProductsInCategory_ItemDataBound(object sender, DataListItemEventArgs e)
{
    // If we have a data item, hide the Label
    if (e.Item.ItemType == ListItemType.Item ||
        e.Item.ItemType == ListItemType.AlternatingItem)
        NoProductsMessage.Visible = false;
}

Tutte le categorie nel database Northwind sono associate a uno o più prodotti. Per testare questa funzionalità, ho modificato manualmente il database Northwind per questa esercitazione, riassegnando tutti i prodotti associati alla categoria Produce (CategoryID = 7) alla categoria Pesce ( =CategoryID 8). Questa operazione può essere eseguita da Esplora server scegliendo Nuova query e usando l'istruzione seguente UPDATE :

UPDATE Products SET
    CategoryID = 8
WHERE CategoryID = 7

Dopo aver aggiornato il database di conseguenza, tornare alla CategoryListMaster.aspx pagina e fare clic sul collegamento Produce. Poiché non sono più presenti prodotti appartenenti alla categoria Produce, verrà visualizzato il messaggio "Non ci sono prodotti per la categoria selezionata..." messaggio, come illustrato nella figura 9.

Viene visualizzato un messaggio se non sono presenti prodotti appartenenti alla categoria selezionata

Figura 9: Viene visualizzato un messaggio se non sono presenti prodotti appartenenti alla categoria selezionata (fare clic per visualizzare l'immagine a dimensione intera)

Riepilogo

Anche se i report master/dettagli possono visualizzare sia i record master che i record di dettaglio in una singola pagina, in molti siti Web sono separati tra due pagine Web. In questa esercitazione è stato illustrato come implementare un report master/dettaglio con le categorie elencate in un elenco puntato usando un ripetitore nella pagina Web "master" e i prodotti associati elencati nella pagina "dettagli". Ogni voce di elenco nella pagina Web master contiene un collegamento alla pagina dei dettagli passata lungo il valore della CategoryID riga.

Nella pagina dei dettagli il recupero di tali prodotti per il fornitore specificato è stato eseguito tramite il ProductsBLL metodo della GetProductsByCategoryID(categoryID) classe. Il valore del categoryID parametro è stato specificato in modo dichiarativo usando il CategoryID valore querystring come origine del parametro. Abbiamo anche esaminato come visualizzare i dettagli delle categorie nella pagina dei dettagli usando un controllo FormView e come visualizzare un messaggio se non sono presenti prodotti appartenenti alla categoria selezionata.

Buon programmatori!

Informazioni sull'autore

Scott Mitchell, autore di sette libri ASP/ASP.NET e fondatore di 4GuysFromRolla.com, lavora con le tecnologie Web Microsoft dal 1998. Scott lavora come consulente indipendente, formatore e scrittore. Il suo ultimo libro è Sams Teach Yourself ASP.NET 2.0 in 24 ore. Può essere raggiunto all'indirizzo mitchell@4GuysFromRolla.com. o tramite il suo blog, disponibile all'indirizzo http://ScottOnWriting.NET.

Grazie speciale...

Questa serie di esercitazioni è stata esaminata da molti revisori utili. I revisori principali di questa esercitazione erano Zack Jones e Liz Shulok. Si è interessati a esaminare i prossimi articoli MSDN? In tal caso, rilasciami una riga in mitchell@4GuysFromRolla.com.