Condividi tramite


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

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 Filtro master /dettaglio in 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" DataKeyField="ProductID" RepeatColumns="2"
    DataSourceID="ProductsInCategoryDataSource" EnableViewState="False"
    runat="server">
    <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, dataList in ProductsForCategoryDetails.aspx non verrà eseguito il rendering, perché l'origine dati non avrà elementi. 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 ha 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à viene assegnata al messaggio da visualizzare nel caso in cui non siano presenti prodotti corrispondenti. È quindi necessario impostare la proprietà Visible a livello di codice in base al fatto che DataList contenga o meno elementi.

A questo scopo, iniziare aggiungendo un'etichetta sotto l'oggetto DataList. Impostare la proprietà su NoProductsMessage e la relativa IDText proprietà su "Non sono presenti prodotti 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 a ProductsInCategory DataList. Questa assegnazione deve essere effettuata 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 dei dati. Tuttavia, né DataList né Repeater dispone di un DataBound evento.

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

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

Protected Sub ProductsInCategory_DataBinding(sender As Object, e As EventArgs) _
    Handles ProductsInCategory.DataBinding
    'Show the Label
    NoProductsMessage.Visible = True
End Sub
 
Protected Sub ProductsInCategory_ItemDataBound(s As Object, e As DataListItemEventArgs) _
    Handles ProductsInCategory.ItemDataBound
    'If we have a data item, hide the Label
    If e.Item.ItemType = ListItemType.Item OrElse e.Item.ItemType = _
        ListItemType.AlternatingItem Then
 
        NoProductsMessage.Visible = False
    End If
End Sub

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, riassegnare tutti i prodotti associati alla categoria Produce ( = 7) alla categoria Pesce (CategoryIDCategoryID = 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, dovrebbe essere 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 full-size)

Riepilogo

Anche se i report master/dettagli possono visualizzare sia i record master che i dettagli 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 elemento 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 categoryID valore del parametro è stato specificato in modo dichiarativo usando il CategoryID valore querystring come origine dei parametri. È stato anche esaminato come visualizzare i dettagli della categoria nella pagina dei dettagli usando FormView e come visualizzare un messaggio se non sono presenti prodotti appartenenti alla categoria selezionata.

Programmazione felice!

Informazioni sull'autore

Scott Mitchell, autore di sette libri ASP/ASP.NET e fondatore di 4GuysFromRolla.com, ha lavorato con le tecnologie Microsoft Web dal 1998. Scott lavora come consulente indipendente, allenatore e scrittore. Il suo ultimo libro è Sams Teach Yourself ASP.NET 2,0 in 24 Ore. Può essere raggiunto a mitchell@4GuysFromRolla.com. o tramite il suo blog, che può essere trovato in http://ScottOnWriting.NET.

Grazie speciali a...

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