Report master o di dettaglio con un elenco puntato di record master e un controllo DataList di dettagli (VB)

di Scott Mitchell

Scarica il PDF

In questa esercitazione verrà compresso il report master/dettaglio a due pagine dell'esercitazione precedente in una singola pagina, che mostra un elenco puntato di nomi di categoria sul lato sinistro dello schermo e i prodotti della categoria selezionati a destra dello schermo.

Introduzione

Nell'esercitazione precedente è stato illustrato come separare un report master/dettaglio tra due pagine. Nella pagina master è stato usato un controllo Repeater per eseguire il rendering di un elenco puntato di categorie. Ogni nome di categoria è un collegamento ipertestuale che, quando si fa clic, consente all'utente di accedere alla pagina dei dettagli, in cui un DataList a due colonne mostra tali prodotti appartenenti alla categoria selezionata.

In questa esercitazione si comprimerà l'esercitazione a due pagine in una singola pagina, che mostra un elenco puntato di nomi di categoria sul lato sinistro della schermata con ogni nome di categoria sottoposto a rendering come LinkButton. Facendo clic su uno dei nomi di categoria LinkButtons si induce un postback e associa i prodotti della categoria selezionata a un oggetto DataList a due colonne a destra della schermata. Oltre a visualizzare ogni nome di categoria, il ripetitore a sinistra mostra il numero di prodotti totali per una determinata categoria (vedere la figura 1).

Il nome della categoria e il numero totale di prodotti vengono visualizzati a sinistra

Figura 1: Il nome della categoria e il numero totale di prodotti vengono visualizzati a sinistra (fare clic per visualizzare l'immagine full-size)

Passaggio 1: Visualizzazione di un ripetitore nella parte sinistra dello schermo

Per questa esercitazione è necessario visualizzare l'elenco puntato delle categorie a sinistra dei prodotti della categoria selezionata. Il contenuto all'interno di una pagina Web può essere posizionato usando tag di paragrafo di elementi HTML standard, spazi di interruzione, <table> s e così via o tramite tecniche CSS (StyleSheet) a catena. Tutte le esercitazioni finora hanno usato tecniche CSS per la posizionamento. Quando è stata creata l'interfaccia utente di spostamento nella pagina master nell'esercitazione Master Pages and Site Navigation è stata usata la posizione assoluta, che indica l'offset di pixel preciso per l'elenco di spostamento e il contenuto principale. In alternativa, CSS può essere usato per posizionare un elemento a destra o a sinistra di un altro tramite spostamento mobile. È possibile visualizzare l'elenco puntato di categorie a sinistra dei prodotti della categoria selezionata mobilendo il ripetitore a sinistra di DataList

Aprire la CategoriesAndProducts.aspx pagina dalla DataListRepeaterFiltering cartella e aggiungere alla pagina un ripetitore e un oggetto DataList. Impostare Il ripetitore su e l'oggetto IDCategories DataList s su CategoryProducts. Passare alla visualizzazione Origine e inserire i controlli Repeater e DataList all'interno dei propri <div> elementi. Ovvero, racchiudere il Ripetitore all'interno di un <div> elemento prima e quindi DataList nel proprio <div> elemento direttamente dopo il Ripetitore. Il markup a questo punto dovrebbe essere simile al seguente:

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

Per float il ripetitore a sinistra di DataList, è necessario usare l'attributo float di stile CSS, ad esempio:

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

Il float: left; valore float del primo <div> elemento a sinistra del secondo. Le width impostazioni e padding-right indicano la prima <div>width s e la quantità di riempimento aggiunta tra il contenuto dell'elemento e il <div> relativo margine destro. Per altre informazioni sugli elementi mobili in CSS, vedere Floatutorial.

Anziché specificare l'impostazione dello stile direttamente tramite l'attributo del style primo <p> elemento, consente di creare invece una nuova classe CSS in Styles.css denominata FloatLeft:

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

È quindi possibile sostituire l'oggetto <div> con <div class="FloatLeft">.

Dopo aver aggiunto la classe CSS e configurato il markup nella CategoriesAndProducts.aspx pagina, passare alla Designer. Verrà visualizzata la spostamento del ripetitore a sinistra dell'oggetto DataList(anche se ora entrambe appaiono come caselle grigie poiché è ancora stato configurato le origini dati o i modelli).

Il ripetitore viene float a sinistra dell'elenco dati

Figura 2: Il ripetitore viene float a sinistra dell'elenco dati (fare clic per visualizzare l'immagine a dimensioni complete)

Passaggio 2: Determinazione del numero di prodotti per ogni categoria

Con il completamento del markup Repeater e DataList, è possibile associare i dati della categoria al controllo Ripetitore. Tuttavia, come illustrato nell'elenco puntato delle categorie nella figura 1, oltre a ogni nome di categoria è necessario visualizzare anche il numero di prodotti associati alla categoria. Per accedere a queste informazioni, è possibile:

  • Determinare queste informazioni dalla classe code-behind della pagina ASP.NET. Dato un particolare categoryID è possibile determinare il numero di prodotti associati chiamando il ProductsBLL metodo della GetProductsByCategoryID(categoryID) classe. Questo metodo restituisce un ProductsDataTable oggetto la cui Count proprietà indica ProductsRow il numero di prodotti presenti, ovvero il numero di prodotti per l'oggetto specificato categoryID. È possibile creare un ItemDataBound gestore eventi per il ripetitore che, per ogni categoria associata al ripetitore, chiama il metodo della GetProductsByCategoryID(categoryID) classe e include il ProductsBLL relativo conteggio nell'output.
  • Aggiornare nell'oggetto CategoriesDataTable DataSet tipizzato per includere una NumberOfProducts colonna. È quindi possibile aggiornare il GetCategories() metodo in CategoriesDataTable per includere queste informazioni o, in alternativa, lasciare GetCategories() come è e creare un nuovo CategoriesDataTable metodo denominato GetCategoriesAndNumberOfProducts().

Esplora entrambe queste tecniche. Il primo approccio è più semplice da implementare perché non è necessario aggiornare il livello di accesso ai dati; tuttavia, richiede più comunicazioni con il database. La chiamata al ProductsBLL metodo della GetProductsByCategoryID(categoryID) classe nel ItemDataBound gestore eventi aggiunge una chiamata di database aggiuntiva per ogni categoria visualizzata nel ripetitore. Con questa tecnica sono disponibili chiamate di database N + 1, dove N è il numero di categorie visualizzate nel ripetitore. Con il secondo approccio, il conteggio dei prodotti viene restituito con informazioni su ogni categoria del metodo (GetCategories()o GetCategoriesAndNumberOfProducts()) della CategoriesBLL classe, causando così un solo viaggio nel database.

Determinazione del numero di prodotti nel gestore eventi ItemDataBound

Determinare il numero di prodotti per ogni categoria nel gestore eventi ItemDataBound ripetitore non richiede modifiche al livello di accesso ai dati esistente. Tutte le modifiche possono essere apportate direttamente all'interno della CategoriesAndProducts.aspx pagina. Iniziare aggiungendo un nuovo oggetto ObjectDataSource denominato CategoriesDataSource tramite lo smart tag di Repeater. Configurare CategoriesDataSource quindi ObjectDataSource in modo che recupera i dati dal CategoriesBLL metodo della GetCategories() classe.

Configurare ObjectDataSource per usare il metodo GetCategories() della classe CategoriesBLL

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

Ogni elemento nel Categories ripetitore deve essere selezionabile e, quando si fa clic, causa la visualizzazione di CategoryProducts Tali prodotti per la categoria selezionata. Questa operazione può essere eseguita eseguendo un collegamento ipertestuale a ogni categoria, collegandosi alla stessa pagina (CategoriesAndProducts.aspx), ma passando la CategoryID querystring, molto simile a quella illustrata nell'esercitazione precedente. Il vantaggio di questo approccio è che una pagina che visualizza un determinato prodotto di categoria può essere segnalibro e indicizzato da un motore di ricerca.

In alternativa, è possibile creare ogni categoria un LinkButton, ovvero l'approccio che verrà usato per questa esercitazione. LinkButton esegue il rendering nel browser dell'utente come collegamento ipertestuale ma, quando si fa clic, induce un postback; nel postback, l'oggetto ObjectDataSource di DataList deve essere aggiornato per visualizzare i prodotti appartenenti alla categoria selezionata. Per questa esercitazione, l'uso di un collegamento ipertestuale ha più senso rispetto all'uso di un LinkButton; tuttavia, potrebbero esserci altri scenari in cui l'uso di un LinkButton è più vantaggioso. Sebbene l'approccio ai collegamenti ipertestuali sia ideale per questo esempio, è possibile esplorare usando LinkButton. Come si vedrà, l'uso di un LinkButton introduce alcune sfide che altrimenti non si verificano con un collegamento ipertestuale. Pertanto, l'uso di un LinkButton in questa esercitazione evidenzia queste sfide e fornisce soluzioni per tali scenari in cui è possibile usare un LinkButton anziché un collegamento ipertestuale.

Nota

È consigliabile ripetere questa esercitazione usando un controllo HyperLink o <a> un elemento al posto di LinkButton.

Il markup seguente mostra la sintassi dichiarativa per Il ripetitore e ObjectDataSource. Si noti che i modelli di Ripetitore eseguono il rendering di un elenco puntato con ogni elemento come LinkButton:

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

Nota

Per questa esercitazione il ripetitore deve disporre del relativo stato di visualizzazione abilitato (notare l'omissione EnableViewState="False" della sintassi dichiarativa del ripetitore). Nel passaggio 3 verrà creato un gestore eventi per l'evento Repeater ItemCommand in cui si aggiornerà l'insieme ObjectDataSource di DataList.SelectParameters Il ripetitore s, tuttavia, non verrà attivato se lo stato di ItemCommandvisualizzazione è disabilitato.

LinkButton con il ID valore della proprietà di ViewCategory non ha il relativo Text set di proprietà. Se avessimo appena voluto visualizzare il nome della categoria, avremmo impostato la proprietà Text dichiarativamente, tramite la sintassi databinding, come segue:

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

Tuttavia, si vuole visualizzare sia il nome della categoria che il numero di prodotti appartenenti a tale categoria. Queste informazioni possono essere recuperate dal gestore eventi del ripetitore eseguendo una chiamata al ProductBLL metodo della ItemDataBoundGetCategoriesByProductID(categoryID) classe e determinando il numero di record restituiti nell'oggetto ProductsDataTablerisultante, come illustrato nel codice seguente:

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

Si inizia assicurandosi di lavorare con un elemento di dati (uno il cui ItemType è Item o AlternatingItem) e quindi fare riferimento all'istanza appena associata all'oggetto CategoriesRow corrente RepeaterItem. Si determina quindi il numero di prodotti per questa categoria creando un'istanza ProductsBLL della classe, chiamando il GetCategoriesByProductID(categoryID) relativo metodo e determinando il numero di record restituiti usando la Count proprietà . Infine, linkButton nell'elementoTemplate è riferimento e la ViewCategory relativa Text proprietà è impostata su CategoryName (NumberOfProductsInCategory), dove NumberOfProductsInCategory viene formattato come numero con valori decimali zero.

Nota

In alternativa, è possibile aggiungere una funzione di formattazione alla classe code-behind della pagina ASP.NET che accetta uno s CategoryName e CategoryID valori di categoria e restituisce la CategoryName concatenazione con il numero di prodotti nella categoria (come determinato chiamando il GetCategoriesByProductID(categoryID) metodo). I risultati di tale funzione di formattazione potrebbero essere assegnati in modo dichiarativo alla proprietà Text di LinkButton sostituendo la necessità del ItemDataBound gestore eventi. Per altre informazioni sull'uso di funzioni di formattazione, fare riferimento a Using TemplateFields in GridView Control o Formatting the DataList and Repeater Based On Data Tutorials (Uso di templateFields in GridView Control o Formattazione di DataList e Ripetitore basato su dati).

Dopo aver aggiunto questo gestore eventi, eseguire un momento per testare la pagina tramite un browser. Si noti come ogni categoria è elencata in un elenco puntato, visualizzando il nome della categoria e il numero di prodotti associati alla categoria (vedere la figura 4).

Vengono visualizzati il nome e il numero di prodotti di ogni categoria

Figura 4: Vengono visualizzati il nome e il numero di prodotti di ogni categoria (fare clic per visualizzare l'immagine full-size)

Aggiornamento diCategoriesDataTableeCategoriesTableAdapterper includere il numero di prodotti per ogni categoria

Anziché determinare il numero di prodotti per ogni categoria come associato al ripetitore, è possibile semplificare questo processo modificando e CategoriesDataTableCategoriesTableAdapter nel livello di accesso ai dati per includere queste informazioni in modo nativo. A questo scopo, è necessario aggiungere una nuova colonna per CategoriesDataTable contenere il numero di prodotti associati. Per aggiungere una nuova colonna a una tabella dati, aprire Typed DataSet (App_Code\DAL\Northwind.xsd), fare clic con il pulsante destro del mouse su DataTable per modificare e scegliere Aggiungi/Colonna. Aggiungere una nuova colonna all'oggetto CategoriesDataTable (vedere la figura 5).

Aggiungere una nuova colonna alle categorieDataSource

Figura 5: Aggiungere una nuova colonna all'oggetto CategoriesDataSource (Fare clic per visualizzare l'immagine full-size)

Verrà aggiunta una nuova colonna denominata Column1, che è possibile modificare digitando semplicemente un nome diverso. Rinominare questa nuova colonna in NumberOfProducts. Successivamente, è necessario configurare le proprietà di questa colonna. Fare clic sulla nuova colonna e passare alla Finestra Proprietà. Modificare la proprietà della DataType colonna da System.String a System.Int32 e impostare la ReadOnly proprietà su True, come illustrato nella figura 6.

Impostare le proprietà DataType e ReadOnly della nuova colonna

Figura 6: Impostare le DataType proprietà e ReadOnly della nuova colonna

Anche se ora CategoriesDataTable include una NumberOfProducts colonna, il relativo valore non viene impostato da alcuna query tableAdapter corrispondente. È possibile aggiornare il GetCategories() metodo per restituire queste informazioni se si desidera che tali informazioni vengano restituite ogni volta che vengono recuperate le informazioni sulle categorie. Se, tuttavia, è sufficiente acquisire il numero di prodotti associati per le categorie in rari casi (ad esempio solo per questa esercitazione), è possibile lasciare GetCategories() così com'è e creare un nuovo metodo che restituisce queste informazioni. Usare questo secondo approccio, creando un nuovo metodo denominato GetCategoriesAndNumberOfProducts().

Per aggiungere questo nuovo GetCategoriesAndNumberOfProducts() metodo, fare clic con il pulsante destro del CategoriesTableAdapter mouse su e scegliere Nuova query. Verrà visualizzata la Configurazione guidata query TableAdapter, che è stata usata numerose volte nelle esercitazioni precedenti. Per questo metodo, avviare la procedura guidata indicando che la query usa un'istruzione SQL ad hoc che restituisce righe.

Creare il metodo usando un'istruzione SQL ad hoc

Figura 7: Creare il metodo usando un'istruzione SQL ad hoc (fare clic per visualizzare l'immagine a dimensione intera)

L'istruzione SQL restituisce righe

Figura 8: L'istruzione SQL restituisce righe (fare clic per visualizzare l'immagine a dimensione intera)

La schermata successiva della procedura guidata richiede l'uso della query. Per restituire i campi , e di CategoryIDogni categoria, insieme al numero di prodotti associati alla categoria, usare l'istruzione seguenteSELECT:DescriptionCategoryName

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

Specificare la query da usare

Figura 9: Specificare la query da usare (fare clic per visualizzare l'immagine a dimensione intera)

Si noti che la sottoquery che calcola il numero di prodotti associati alla categoria viene aliasata come NumberOfProducts. Questa corrispondenza di denominazione fa sì che il valore restituito da questa sottoquery sia associato CategoriesDataTable alla colonna s NumberOfProducts .

Dopo aver immesso questa query, l'ultimo passaggio consiste nel scegliere il nome del nuovo metodo. Usare FillWithNumberOfProducts e GetCategoriesAndNumberOfProducts per compilare una tabella DataTable e restituire rispettivamente un modello DataTable.

Denominare i nuovi metodi TableAdapter FillWithNumberOfProducts e GetCategoriesAndNumberOfProducts

Figura 10: Denominare i nuovi metodi FillWithNumberOfProducts tableAdapter e GetCategoriesAndNumberOfProducts (fare clic per visualizzare l'immagine a dimensione intera)

A questo punto il livello di accesso ai dati è stato esteso per includere il numero di prodotti per categoria. Poiché tutti i livelli di presentazione instradano tutte le chiamate a DAL tramite un livello di logica di business separato, è necessario aggiungere un metodo corrispondente GetCategoriesAndNumberOfProducts alla CategoriesBLL classe :

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

Dopo aver completato DAL e BLL, siamo pronti per associare questi dati al Categories Repeater in CategoriesAndProducts.aspx! Se è già stato creato un oggetto ObjectDataSource per Repeater dalla sezione Determinazione del numero di prodotti nella ItemDataBound sezione Gestore eventi, eliminare questa proprietà ObjectDataSource e rimuovere l'impostazione della DataSourceID proprietà Repeater; rimuovere anche l'evento Repeater dal ItemDataBound gestore eventi rimuovendo la Handles Categories.OnItemDataBound sintassi nella classe code-behind ASP.NET.

Con repeater nuovamente nello stato originale, aggiungere un nuovo ObjectDataSource denominato CategoriesDataSource tramite lo smart tag repeater. Configurare ObjectDataSource per l'uso della CategoriesBLL classe , ma anziché usare il GetCategories() metodo , usare GetCategoriesAndNumberOfProducts() invece (vedere la figura 11).

Configurare ObjectDataSource per l'utilizzo del metodo GetCategoriesAndNumberOfProducts

Figura 11: Configurare ObjectDataSource per l'uso del metodo (fare clic per visualizzare l'immagineGetCategoriesAndNumberOfProducts a dimensione intera)

Aggiornare quindi in ItemTemplate modo che la proprietà LinkButton venga Text assegnata in modo dichiarativo usando la sintassi databinding e includa sia i CategoryNameNumberOfProducts campi dati che . Il markup dichiarativo completo per Repeater e CategoriesDataSource ObjectDataSource segue:

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

L'output di cui è stato eseguito il rendering aggiornando DAL per includere una NumberOfProducts colonna equivale all'uso dell'approccio ItemDataBound del gestore eventi (fare riferimento alla figura 4 per visualizzare una schermata del ripetitore che mostra i nomi di categoria e il numero di prodotti).

Passaggio 3: Visualizzazione dei prodotti della categoria selezionata

A questo punto, Categories il ripetitore visualizza l'elenco delle categorie insieme al numero di prodotti in ogni categoria. Repeater usa un linkbutton per ogni categoria che, quando si fa clic, provoca un postback, a questo punto è necessario visualizzare tali prodotti per la categoria selezionata in CategoryProducts DataList.

Una sfida per noi è come fare in modo che DataList visualizzi solo i prodotti per la categoria selezionata. In Master/Detail Using a Selectable Master GridView with a Details DetailsView tutorial we saw how to build a GridView the rows could be selected, with the selected row s details being display in a DetailsView on the same page. GridView s ObjectDataSource ha restituito informazioni su tutti i prodotti utilizzando il ProductsBLL metodo s GetProducts() mentre DetailsView s ObjectDataSource ha recuperato informazioni sul prodotto selezionato utilizzando il GetProductsByProductID(productID) metodo . Il valore del productID parametro è stato fornito in modo dichiarativo associandolo al valore della proprietà gridView.SelectedValue Sfortunatamente, repeater non dispone di una SelectedValue proprietà e non può fungere da origine di parametri.

Nota

Questo è uno di questi problemi che vengono visualizzati quando si usa LinkButton in un repeater. Se invece è stato usato un collegamento ipertestuale per passare tramite CategoryID la stringa di query, è possibile usare il campo QueryString come origine per il valore del parametro.

Prima di preoccuparsi della mancanza di una SelectedValue proprietà per Repeater, tuttavia, è prima possibile associare DataList a objectDataSource e specificarne ItemTemplate.

Dallo smart tag di DataList scegliere di aggiungere un nuovo ObjectDataSource denominato CategoryProductsDataSource e configurarlo per l'uso del ProductsBLL metodo della GetProductsByCategoryID(categoryID) classe. Poiché DataList in questa esercitazione offre un'interfaccia di sola lettura, è possibile impostare gli elenchi a discesa nelle schede INSERT, UPDATE e DELETE su (Nessuno).

Configurare objectDataSource per l'uso del metodo GetProductsByCategoryID(categoryID) della classe ProductsBLL

Figura 12: Configurare ObjectDataSource per l'uso ProductsBLL del metodo della GetProductsByCategoryID(categoryID) classe (fare clic per visualizzare l'immagine a dimensione intera)

Poiché il GetProductsByCategoryID(categoryID) metodo prevede un parametro di input (categoryID), la procedura guidata Configura origine dati consente di specificare l'origine del parametro. Se le categorie sono state elencate in un controllo GridView o in un oggetto DataList, l'elenco a discesa Origine parametri è stato impostato su Control e controlID sul ID controllo Web dei dati. Tuttavia, poiché repeater non dispone di una SelectedValue proprietà, non può essere usata come origine di parametri. Se si seleziona, l'elenco a discesa ControlID contiene un solo controllo ID``CategoryProducts, dell'oggetto ID DataList.

Per il momento, impostare l'elenco a discesa Origine parametri su Nessuno. Questo valore di parametro verrà assegnato a livello di codice quando si fa clic su una categoria LinkButton nel ripetitore.

Non specificare un'origine parametro per il parametro categoryID

Figura 13: Non specificare un'origine parametro per il categoryID parametro (fare clic per visualizzare l'immagine a dimensione intera)

Dopo aver completato la procedura guidata Configura origine dati, Visual Studio genera automaticamente l'oggetto DataList s ItemTemplate. Sostituire questa impostazione predefinita ItemTemplate con il modello usato nell'esercitazione precedente. Impostare anche la proprietà DataList s RepeatColumns su 2. Dopo aver apportato queste modifiche, il markup dichiarativo per DataList e l'oggetto ObjectDataSource associato dovrebbero essere simili ai seguenti:

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

Attualmente, il CategoryProductsDataSource parametro objectDataSource s categoryID non viene mai impostato, quindi non viene visualizzato alcun prodotto durante la visualizzazione della pagina. È necessario impostare questo valore di parametro in base all'oggetto CategoryID della categoria selezionata nel Repeater. Ciò introduce due sfide: in primo luogo, come determinare quando è stato fatto clic su un linkbutton nel ripetitore; ItemTemplate e in secondo luogo, come è possibile determinare l'oggetto CategoryID della categoria corrispondente su cui è stato fatto clic su LinkButton?

Il pulsante LinkButton come i controlli Button e ImageButton ha un Click evento e un Command evento. L'evento Click è progettato per notare semplicemente che è stato fatto clic su LinkButton. A volte, tuttavia, oltre a notare che è stato fatto clic su LinkButton, è necessario passare anche alcune informazioni aggiuntive al gestore eventi. In questo caso, alle proprietà e CommandArgument alle proprietà LinkButton CommandName è possibile assegnare queste informazioni aggiuntive. Quindi, quando si fa clic su LinkButton, il relativo Command evento viene generato (anziché il relativo Click evento) e il gestore eventi viene passato ai valori delle CommandName proprietà e CommandArgument .

Quando un Command evento viene generato dall'interno di un modello nel Repeater, l'evento Repeater viene ItemCommand generato e viene passato i CommandName valori e CommandArgument del pulsante o Button o ImageButton selezionato. Pertanto, per determinare quando è stato fatto clic su un linkbutton di categoria nel ripetitore, è necessario eseguire le operazioni seguenti:

  1. Impostare la CommandName proprietà di LinkButton in Repeater s ItemTemplate su un valore (ho usato ListProducts). Impostando questo CommandName valore, l'evento LinkButton viene Command generato quando si fa clic su LinkButton.
  2. Impostare la proprietà LinkButton sul CommandArgument valore dell'elemento corrente.CategoryID
  3. Creare un gestore eventi per l'evento Repeater.ItemCommand Nel gestore eventi impostare il CategoryProductsDataSource parametro ObjectDataSource sul CategoryID valore dell'oggetto passato.CommandArgument

Il markup seguente ItemTemplate per Il ripetitore categorie implementa i passaggi 1 e 2. Si noti che al valore viene assegnato l'elemento CommandArgumentCategoryID di dati usando la sintassi databinding:

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

Ogni volta che si crea un ItemCommand gestore eventi, è consigliabile controllare sempre il valore in ingresso CommandName perché qualsiasiCommand evento generato da qualsiasi evento Button, LinkButton o ImageButton all'interno del Repeater causerà l'attivazione dell'evento ItemCommand . Anche se attualmente è disponibile un solo linkButton, in futuro microsoft (o un altro sviluppatore del team) potrebbe aggiungere altri controlli Web pulsante al Repeater che, quando si fa clic, genera lo stesso ItemCommand gestore eventi. Pertanto, è consigliabile assicurarsi sempre di controllare la proprietà e procedere solo con la CommandName logica programmatica se corrisponde al valore previsto.

Dopo aver verificato che il valore passato CommandName sia uguale a ListProducts, il gestore eventi assegna quindi il CategoryProductsDataSource parametro ObjectDataSource al CategoryID valore dell'oggetto passato.CommandArgument Questa modifica apportata a ObjectDataSource fa SelectParameters sì che DataList venga riassociato automaticamente all'origine dati, mostrando i prodotti per la categoria appena selezionata.

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

Con queste aggiunte, il nostro tutorial è completo! Provarlo in un browser. Nella figura 14 viene visualizzata la schermata quando si visita per la prima volta la pagina. Poiché una categoria non è ancora selezionata, non vengono visualizzati prodotti. Facendo clic su una categoria, ad esempio Produce, tali prodotti vengono visualizzati nella categoria Product in una visualizzazione a due colonne (vedere la figura 15).

Nessun prodotto viene visualizzato quando si visita per la prima volta la pagina

Figura 14: Nessun prodotto viene visualizzato quando si visita per la prima volta la pagina (fare clic per visualizzare l'immagine a dimensione intera)

Facendo clic sulla categoria Produce Elenchi i prodotti corrispondenti a destra

Figura 15: Fare clic sulla categoria Produce Elenchi i prodotti corrispondenti a destra (fare clic per visualizzare l'immagine a dimensione intera)

Riepilogo

Come illustrato in questa esercitazione e in quella precedente, i report master/dettagli possono essere distribuiti in due pagine o consolidati su uno. La visualizzazione di un report master/dettagli in una singola pagina presenta tuttavia alcune problematiche relative al modo migliore per il layout dei record master e dettagli nella pagina. In Master/Detail Using a Selectable Master GridView with a Details DetailsView tutorial we had the details records appear above the master records; in questa esercitazione sono state usate tecniche CSS per fare in modo che i record master siano float a sinistra dei dettagli.

Oltre alla visualizzazione di report master/dettagli, è stata anche possibile esplorare come recuperare il numero di prodotti associati a ogni categoria e come eseguire la logica lato server quando viene fatto clic su LinkButton (o Button o ImageButton) all'interno di un ripetitore.

Questa esercitazione completa l'esame dei report master/dettagli con DataList e Repeater. Il set successivo di esercitazioni illustra come aggiungere modifiche ed eliminare funzionalità al controllo DataList.

Programmazione felice!

Altre informazioni

Per altre informazioni sugli argomenti illustrati in questa esercitazione, vedere le risorse seguenti:

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

Questa serie di esercitazioni è stata esaminata da molti revisori utili. Il revisore principale per questa esercitazione era Zack Jones. Interessati a esaminare i prossimi articoli MSDN? In tal caso, lasciami una riga in mitchell@4GuysFromRolla.com.