Condividi tramite


Aggiunta di una colonna GridView con pulsanti di opzione (C#)

di Scott Mitchell

Scaricare il PDF

Questa esercitazione illustra come aggiungere una colonna di pulsanti di opzione a un controllo GridView per fornire all'utente un modo più intuitivo per selezionare una singola riga di GridView.

Introduzione

Il controllo GridView offre una grande quantità di funzionalità predefinite. Include diversi campi per la visualizzazione di testo, immagini, collegamenti ipertestuali e pulsanti. Supporta modelli per un'ulteriore personalizzazione. Con pochi clic del mouse, è possibile creare un controllo GridView in cui ogni riga può essere selezionata tramite un pulsante o per abilitare la modifica o l'eliminazione di funzionalità. Nonostante la pletora di funzionalità fornite, spesso ci saranno situazioni in cui sarà necessario aggiungere funzionalità aggiuntive non supportate. In questa esercitazione e i due successivi si esaminerà come migliorare la funzionalità di GridView per includere funzionalità aggiuntive.

Questa esercitazione e quella successiva si concentrano sul miglioramento del processo di selezione delle righe. Come esaminato nel Master/Detail usando un controllo GridView Master selezionabile con un Details DetailView, è possibile aggiungere un CommandField al GridView che include il pulsante Seleziona. Quando si fa clic, viene eseguito un postback e la proprietà gridView s SelectedIndex viene aggiornata all'indice della riga su cui è stato fatto clic sul pulsante Seleziona. Nell'esercitazione Master/Detail Using a Selectable Master GridView with a Details DetailView, abbiamo visto come utilizzare questa funzionalità per visualizzare i dettagli della riga selezionata nella GridView.

Anche se il pulsante Seleziona funziona in molte situazioni, potrebbe non funzionare anche per altri utenti. Invece di usare un pulsante, vengono comunemente usati due altri elementi dell'interfaccia utente per la selezione: il pulsante di opzione e la casella di controllo. È possibile aumentare GridView in modo che invece di un pulsante Seleziona ogni riga contenga un pulsante di opzione o una casella di controllo. Negli scenari in cui l'utente può selezionare solo uno dei record nella vista griglia, il pulsante di opzione (radio button) potrebbe essere preferibile rispetto al pulsante Seleziona. In situazioni in cui l'utente può potenzialmente selezionare più record, ad esempio in un'applicazione di posta elettronica basata sul Web, in cui un utente potrebbe voler selezionare più messaggi per eliminare la casella di controllo offre funzionalità non disponibili dal pulsante Seleziona o dalle interfacce utente del pulsante di opzione.

Questa esercitazione illustra come aggiungere una colonna di pulsanti di opzione a GridView. L'esercitazione in corso illustra l'uso delle caselle di controllo.

Passaggio 1: Creare le pagine Web di GridView migliorate

Prima di iniziare a migliorare GridView per includere una colonna di pulsanti di opzione, è necessario prima di tutto creare le pagine ASP.NET nel progetto del sito Web che saranno necessarie per questa esercitazione e le due successive. Per iniziare, aggiungere una nuova cartella denominata EnhancedGridView. Aggiungere quindi le pagine di ASP.NET seguenti a tale cartella, assicurandosi di associare ogni pagina alla Site.master pagina master:

  • Default.aspx
  • RadioButtonField.aspx
  • CheckBoxField.aspx
  • InsertThroughFooter.aspx

Aggiungere le pagine di ASP.NET per le esercitazioni SqlDataSource-Related

Figura 1: Aggiungere le pagine ASP.NET per le esercitazioni SqlDataSource-Related

Come nelle altre cartelle, Default.aspx nella cartella EnhancedGridView elenca le esercitazioni nella relativa sezione. Tenere presente che il SectionLevelTutorialListing.ascx controllo utente fornisce questa funzionalità. Aggiungere quindi questo controllo utente a Default.aspx trascinandolo da Esplora soluzioni nella visualizzazione di progettazione della pagina.

Aggiungere il controllo utente SectionLevelTutorialListing.ascx a Default.aspx

Figura 2: Aggiungere il SectionLevelTutorialListing.ascx controllo utente a Default.aspx (fare clic per visualizzare l'immagine a dimensione intera)

Infine, aggiungi queste quattro pagine come voci nel file Web.sitemap. In particolare, aggiungere il markup seguente dopo l'uso del controllo <siteMapNode>SqlDataSource :

<siteMapNode 
    title="Enhancing the GridView" 
    url="~/EnhancedGridView/Default.aspx" 
    description="Augment the user experience of the GridView control.">
    <siteMapNode 
        url="~/EnhancedGridView/RadioButtonField.aspx" 
        title="Selection via a Radio Button Column" 
        description="Explore how to add a column of radio buttons in the GridView." />
    <siteMapNode 
        url="~/EnhancedGridView/CheckBoxField.aspx" 
        title="Selection via a Checkbox Column" 
        description="Select multiple records in the GridView by using a column of 
            checkboxes." />
    <siteMapNode 
        url="~/EnhancedGridView/InsertThroughFooter.aspx" 
        title="Add New Records through the Footer" 
        description="Learn how to allow users to add new records through the 
            GridView's footer." />
</siteMapNode>

Dopo l'aggiornamento Web.sitemap, dedica qualche minuto per visitare il sito web delle esercitazioni tramite un browser. Il menu a sinistra include ora elementi per le esercitazioni di modifica, inserimento ed eliminazione.

La mappa del sito include ora le voci per il miglioramento delle esercitazioni su GridView

Figura 3: La mappa del sito include ora le voci per il miglioramento delle esercitazioni su GridView

Passaggio 2: Visualizzazione dei fornitori in un elemento GridView

Per questa esercitazione, costruiamo un GridView che elenca i fornitori dagli Stati Uniti, con ogni riga del GridView che presenta un pulsante di opzione. Dopo aver selezionato un fornitore tramite il pulsante di opzione, l'utente può visualizzare i prodotti del fornitore facendo clic su un pulsante. Anche se questo compito può sembrare semplice, ci sono una serie di sottigliezze che lo rendono particolarmente difficile. Prima di approfondire queste sottigliezze, è possibile ottenere un gridView che elenca i fornitori.

Per iniziare, aprire la RadioButtonField.aspx pagina nella EnhancedGridView cartella trascinando GridView dal Toolbox sul Designer. Impostare GridView s ID su Suppliers e, dallo smart tag, scegliere di creare una nuova origine dati. In particolare, creare un ObjectDataSource denominato SuppliersDataSource che estrae i dati dall'oggetto SuppliersBLL .

Creare un nuovo ObjectDataSource denominato SuppliersDataSource

Figura 4: Creare un nuovo oggettoDataSource denominato SuppliersDataSource (fare clic per visualizzare l'immagine a dimensione intera)

Screenshot della finestra Configura origine dati - SuppliersDataSource con l'oggetto business SuppliersBLL selezionato e il pulsante Avanti evidenziato.

Figura 5: Configurare ObjectDataSource per l'uso della classe (SuppliersBLL a dimensione intera)

Poiché si vogliono elencare solo i fornitori negli Stati Uniti, scegliere il GetSuppliersByCountry(country) metodo dall'elenco a discesa nella scheda SELECT.

Screenshot della finestra Configura origine dati - SuppliersDataSource con la scheda SELECT aperta. L'opzione del metodo GetSupplierByCountry è selezionata e il pulsante Avanti è evidenziato.

Figura 6: Configurare ObjectDataSource per l'uso della classe (SuppliersBLL a dimensione intera)

Nella scheda UPDATE selezionare l'opzione (Nessuno) e fare clic su Avanti.

Screenshot della finestra Configura origine dati - SuppliersDataSource con la scheda UPDATE aperta. L'opzione del metodo (Nessuno) è selezionata e il pulsante Avanti è evidenziato.

Figura 7: Configurare ObjectDataSource per l'uso della classe (SuppliersBLL a dimensione intera)

Poiché il GetSuppliersByCountry(country) metodo accetta un parametro, la procedura guidata Configura origine dati richiede l'origine di tale parametro. Per specificare un valore codificato (USA, in questo esempio), lasciare l'elenco a discesa Origine parametro impostato su Nessuno e immettere il valore di default nella casella di testo. Fare clic su Fine per completare la procedura guidata.

Usare USA come valore predefinito per il parametro country

Figura 8: Usare USA come valore predefinito per il parametro (country a dimensione intera)

Al termine della procedura guidata, GridView includerà un BoundField per ognuno dei campi dati del fornitore. Rimuovere tutto tranne i CompanyName, City e Country BoundFields e rinominare la proprietà del BoundField CompanyName in Supplier. Dopo questa operazione, la sintassi dichiarativa GridView e ObjectDataSource dovrebbe essere simile alla seguente.

<asp:GridView ID="Suppliers" runat="server" AutoGenerateColumns="False"
    DataKeyNames="SupplierID" DataSourceID="SuppliersDataSource" 
    EnableViewState="False">
    <Columns>
        <asp:BoundField DataField="CompanyName" HeaderText="Supplier" 
            SortExpression="CompanyName" />
        <asp:BoundField DataField="City" HeaderText="City" 
            SortExpression="City" />
        <asp:BoundField DataField="Country" HeaderText="Country" 
            SortExpression="Country" />
    </Columns>
</asp:GridView>
<asp:ObjectDataSource ID="SuppliersDataSource" runat="server" 
    OldValuesParameterFormatString="original_{0}"
    SelectMethod="GetSuppliersByCountry" TypeName="SuppliersBLL">
    <SelectParameters>
        <asp:Parameter DefaultValue="USA" Name="country" Type="String" />
    </SelectParameters>
</asp:ObjectDataSource>

Per questa esercitazione, consentire all'utente di visualizzare i prodotti del fornitore selezionato nella stessa pagina dell'elenco dei fornitori o in una pagina diversa. Per soddisfare questa esigenza, aggiungere due controlli Web di tipo pulsante alla pagina. Ho impostato i ID di questi due pulsanti su ListProducts e SendToProducts, con l'idea che quando si fa clic su ListProducts, si verificherà un postback e i prodotti del fornitore selezionato verranno elencati nella stessa pagina, mentre quando si fa clic su SendToProducts, l'utente verrà portato su un'altra pagina in cui sono elencati i prodotti.

La figura 9 mostra i Suppliers controlli GridView e i due controlli Web Button quando vengono visualizzati tramite un browser.

I fornitori degli Stati Uniti hanno il nome, la città e le informazioni sul paese elencate

Figura 9: I fornitori degli Stati Uniti hanno il nome, la città e le informazioni sul paese elencate (fare clic per visualizzare l'immagine a dimensione intera)

Passaggio 3: Aggiunta di una colonna di pulsanti di opzione

A questo punto, Suppliers GridView ha tre BoundFields che visualizzano il nome della società, la città e il paese di ogni fornitore negli Stati Uniti. Tuttavia, manca ancora una colonna di pulsanti di opzione. Purtroppo, la GridView non include un RadioButtonField predefinito, altrimenti potremmo semplicemente aggiungerlo alla griglia e aver finito. Invece, possiamo aggiungere un TemplateField e configurare il suo ItemTemplate per mostrare un pulsante di opzione, generando un pulsante di opzione per ogni riga del GridView.

Inizialmente, si potrebbe presupporre che l'interfaccia utente desiderata possa essere implementata aggiungendo un controllo Web RadioButton a ItemTemplate di un oggetto TemplateField. Anche se questo aggiungerà effettivamente un singolo pulsante di opzione a ogni riga di GridView, i pulsanti di opzione non possono essere raggruppati e pertanto non si escludono a vicenda. Ovvero, un utente finale è in grado di selezionare più pulsanti di opzione contemporaneamente da GridView.

Anche se l'uso di un TemplateField con controlli Web RadioButton non offre le funzionalità necessarie, implementiamo comunque questo approccio, poiché è utile esaminare perché i pulsanti di opzione risultanti non sono raggruppati. Per iniziare, aggiungere un oggetto TemplateField a Suppliers GridView, rendendolo il campo più a sinistra. Successivamente, dallo smart tag GridView, fare clic sul collegamento Modifica modelli e trascinare un controllo Web RadioButton dalla casella degli strumenti nel ItemTemplate di TemplateField (vedere la figura 10). Impostare la proprietà RadioButton su IDRowSelector e la GroupName proprietà su SuppliersGroup.

Aggiungere un controllo Web RadioButton all'ItemTemplate

Figura 10: Aggiungere un controllo Web RadioButton a ItemTemplate (fare clic per visualizzare l'immagine a dimensione intera)

Dopo aver apportato queste aggiunte tramite la finestra di progettazione, il markup di GridView dovrebbe essere simile al seguente:

<asp:GridView ID="Suppliers" runat="server" AutoGenerateColumns="False"
    DataKeyNames="SupplierID" DataSourceID="SuppliersDataSource" 
    EnableViewState="False">
    <Columns>
        <asp:TemplateField>
            <ItemTemplate>
                <asp:RadioButton ID="RowSelector" runat="server" 
                    GroupName="SuppliersGroup" />
            </ItemTemplate>
        </asp:TemplateField>
        <asp:BoundField DataField="CompanyName" HeaderText="Supplier" 
            SortExpression="CompanyName" />
        <asp:BoundField DataField="City" HeaderText="City" 
            SortExpression="City" />
        <asp:BoundField DataField="Country" HeaderText="Country" 
            SortExpression="Country" />
    </Columns>
</asp:GridView>

La proprietà RadioButton GroupName viene utilizzata per raggruppare una serie di pulsanti di opzione. Tutti i controlli RadioButton con lo stesso GroupName valore vengono considerati raggruppati. È possibile selezionare un solo pulsante di opzione da un gruppo alla volta. La proprietà GroupName specifica il valore dell'attributo name del pulsante di opzione renderizzato. Il browser esamina gli attributi name dei pulsanti radio per determinare i raggruppamenti dei pulsanti radio.

Con il controllo Web RadioButton aggiunto a ItemTemplate, visitare questa pagina tramite un browser e fare clic sui pulsanti di opzione nelle righe della griglia. Si noti che i pulsanti di opzione non sono raggruppati, rendendo possibile selezionare tutte le righe, come illustrato nella Figura 11.

I pulsanti di opzione di GridView non sono raggruppati

Figura 11: I pulsanti di opzione di GridView non sono raggruppati (fare clic per visualizzare l'immagine a dimensione intera)

Il motivo per cui i pulsanti di opzione non sono raggruppati è che gli attributi name sottoposti a rendering sono diversi, nonostante abbiano la stessa impostazione della proprietà GroupName. Per visualizzare queste differenze, utilizzare la funzione Visualizza sorgente nel browser ed esaminare il markup del pulsante di scelta.

<input id="ctl00_MainContent_Suppliers_ctl02_RowSelector" 
    name="ctl00$MainContent$Suppliers$ctl02$SuppliersGroup" 
    type="radio" value="RowSelector" />
<input id="ctl00_MainContent_Suppliers_ctl03_RowSelector" 
    name="ctl00$MainContent$Suppliers$ctl03$SuppliersGroup" 
    type="radio" value="RowSelector" />
<input id="ctl00_MainContent_Suppliers_ctl04_RowSelector" 
    name="ctl00$MainContent$Suppliers$ctl04$SuppliersGroup" 
    type="radio" value="RowSelector" />
<input id="ctl00_MainContent_Suppliers_ctl05_RowSelector" 
    name="ctl00$MainContent$Suppliers$ctl05$SuppliersGroup" 
    type="radio" value="RowSelector" />

Si noti che gli name attributi e id non sono i valori esatti specificati nella finestra Proprietà, ma vengono anteporti a un numero di altri ID valori. I valori aggiuntivi ID aggiunti nella parte anteriore degli attributi renderizzati id e name sono i controlli genitori ID dei pulsanti radio GridViewRowID, il GridView ID, il controllo Contenuto ID e il Web Form ID. Questi ID vengono aggiunti affinché ogni controllo Web reso nel GridView abbia valori id e name univoci.

Ogni controllo di cui è stato eseguito il rendering richiede un diverso name e id perché questo è il modo in cui il browser identifica in modo univoco ogni controllo sul lato client e il modo in cui comunica al server web quale azione o modifica è avvenuta durante il postback. Si supponga, ad esempio, di voler eseguire codice lato server ogni volta che viene modificato lo stato di selezione di un RadioButton. Possiamo ottenere questo impostando la proprietà di RadioButton su AutoPostBacktrue e creando un gestore eventi per l'evento CheckChanged. Tuttavia, se i valori resi di name e id per tutti i pulsanti di opzione fossero gli stessi, al momento del postback non sarebbe possibile determinare quale pulsante radio specifico è stato cliccato.

In sintesi, non è possibile creare una colonna di bottoni di opzione in un controllo GridView utilizzando il controllo Web RadioButton. È invece necessario usare tecniche piuttosto arcaiche per assicurarsi che il markup appropriato venga inserito in ogni riga gridView.

Annotazioni

Come il controllo Web RadioButton, il controllo HTML del pulsante di opzione, quando viene aggiunto a un modello, includerà l'attributo univoco name , rendendo i pulsanti di opzione nella griglia non raggruppati. Se non si ha familiarità con i controlli HTML, è possibile ignorare questa nota, poiché i controlli HTML vengono usati raramente, soprattutto in ASP.NET 2.0. Tuttavia, se si è interessati a saperne di più, vedere K. Scott Allen blog entry Web Controls and HTML Controls (Controlli Web e controlli HTML).

Uso di un controllo Literal per inserire il markup del pulsante radio

Per raggruppare correttamente tutti i pulsanti di opzione all'interno di GridView, è necessario inserire manualmente il markup dei pulsanti di opzione in ItemTemplate. Ogni pulsante di opzione richiede lo stesso name attributo, ma deve avere un attributo univoco id (nel caso in cui si voglia accedere a un pulsante di opzione tramite script sul lato client). Dopo che un utente seleziona un pulsante di scelta e pubblica la pagina, il browser invierà di nuovo il valore dell'attributo del pulsante di scelta selezionatovalue. Di conseguenza, ogni pulsante di opzione richiederà un attributo univoco value . Infine, al postback, è necessario assicurarsi di aggiungere l'attributo checked all'unico pulsante di opzione che è stato selezionato, altrimenti, dopo che l'utente ha effettuato una selezione e ha effettuato il postback, i pulsanti di opzione torneranno al loro stato predefinito (tutti i pulsanti non selezionati).

Esistono due approcci che è possibile adottare per inserire markup di basso livello in un modello. Uno consiste nell'eseguire una combinazione di markup e chiamate ai metodi di formattazione definiti nella classe code-behind. Questa tecnica è stata discussa per la prima volta nel tutorial Uso di TemplateFields nel controllo GridView. In questo caso potrebbe essere simile al seguente:

<input type="radio" id='<%# GetUniqueRadioButtonID(...) %>' 
    name='SuppliersGroup' value='<%# GetRadioButtonValue(...) %>' ... />

Qui, GetUniqueRadioButton e GetRadioButtonValue sarebbero metodi definiti nella classe code-behind che restituiscono i valori appropriati dell'attributo id e value per ciascun pulsante di opzione. Questo approccio funziona bene per l'assegnazione degli attributi id e value, ma presenta delle limitazioni quando si tratta di specificare il valore dell'attributo checked perché la sintassi di associazione dati viene eseguita solo quando i dati vengono associati per la prima volta al GridView. Pertanto, se gridView ha lo stato di visualizzazione abilitato, i metodi di formattazione verranno attivati solo quando la pagina viene caricata per la prima volta (o quando GridView viene riassegnata in modo esplicito all'origine dati) e pertanto la funzione che imposta l'attributo checked non verrà chiamata al postback. Si tratta di un problema piuttosto sottile e un po ' oltre l'ambito di questo articolo, quindi lo lascerò a questo. Tuttavia, ti incoraggio a provare a usare l'approccio precedente e a seguirlo fino al punto in cui ti blocchi. Anche se un esercizio di questo tipo non ti avvicina a una versione funzionante, contribuirà a promuovere una comprensione più approfondita del ciclo di vita di GridView e del databinding.

L'altro approccio all'inserimento di markup personalizzati di basso livello in un modello e all'approccio che verrà usato per questa esercitazione consiste nell'aggiungere un controllo Literal al modello. Quindi, nel gestore eventi GridViewRowCreated o RowDataBound, il controllo Literal può essere accesso programmaticamente e la proprietà Text impostata sul markup da generare.

Inizia rimuovendo il controllo RadioButton da TemplateField ItemTemplate, sostituendolo con un controllo Literal. Impostare il controllo Literal s ID su RadioButtonMarkup.

Aggiungere un controllo letterale a ItemTemplate

Figura 12: Aggiungere un controllo letterale al ItemTemplate (fare clic qui per visualizzare l'immagine a dimensione intera)

Creare quindi un gestore eventi per l'evento GridView.RowCreated L'evento RowCreated viene generato una volta per ogni riga aggiunta, indipendentemente dal fatto che i dati vengano reinterpretati in GridView. Questo significa che anche in un postback, quando i dati vengono ricaricati dallo stato di visualizzazione, l'evento RowCreated è ancora attivato e questo è il motivo per cui viene utilizzato al posto di RowDataBound (che viene generato solo quando i dati sono associati esplicitamente al controllo Web dati).

In questo gestore eventi si vuole procedere solo se si tratta di una riga di dati. Vogliamo fare riferimento programmaticamente al controllo RadioButtonMarkup Literal per ogni riga di dati e impostarne la proprietà Text sul markup da generare. Come mostrato nel codice seguente, il markup generato crea un radio button il cui attributo name è impostato su SuppliersGroup, il cui attributo id è impostato su RowSelectorX, dove X è l'indice della riga GridView, e il cui attributo value è impostato sull'indice della riga GridView.

protected void Suppliers_RowCreated(object sender, GridViewRowEventArgs e)
{
    if (e.Row.RowType == DataControlRowType.DataRow)
    {
        // Grab a reference to the Literal control
        Literal output = (Literal)e.Row.FindControl("RadioButtonMarkup");
        // Output the markup except for the "checked" attribute
        output.Text = string.Format(
            @"<input type="radio" name="SuppliersGroup" " +
            @"id="RowSelector{0}" value="{0}" />", e.Row.RowIndex);
    }
}

Quando viene selezionata una riga del GridView e si verifica un postback, ci interessa il SupplierID del fornitore selezionato. Pertanto, si potrebbe pensare che il valore di ogni pulsante di opzione dovrebbe essere l'effettivo SupplierID (anziché l'indice della riga GridView). Anche se ciò può funzionare in determinate circostanze, sarebbe un rischio per la sicurezza accettare e elaborare in modo cieco un oggetto SupplierID. Il nostro GridView, ad esempio, elenca solo i fornitori negli Stati Uniti. Tuttavia, se il SupplierID è passato direttamente dal pulsante di opzione, cosa impedisce a un utente malizioso di modificare il valore SupplierID inviato al postback? Usando l'indice di riga come value, e poi ottenendo il SupplierID durante il postback dalla raccolta DataKeys, possiamo assicurarci che l'utente utilizzi solo uno dei valori SupplierID associati a una delle righe del GridView.

Dopo aver aggiunto questo codice del gestore eventi, provare la pagina in un browser. Prima di tutto, si noti che è possibile selezionare un solo pulsante radio nella griglia alla volta. Tuttavia, quando si seleziona un pulsante di opzione e si fa clic su uno dei pulsanti, si verifica un postback e tutti i pulsanti di opzione ripristinano il proprio stato iniziale (ovvero, al postback, il pulsante di opzione selezionato non è più selezionato). Per risolvere questo problema, è necessario modificare il gestore eventi RowCreated in modo che ispezioni l'indice del radio button selezionato inviato dal postback e aggiunga l'attributo checked="checked" al markup output quando l'indice di riga corrisponde.

Quando si verifica un postback, il browser restituisce il name e il value del pulsante di opzione selezionato. Il valore può essere recuperato a livello di codice tramite Request.Form["name"]. La Request.Form proprietà fornisce un oggetto NameValueCollection che rappresenta le variabili del modulo. Le variabili del modulo sono i nomi e i valori dei campi modulo nella pagina Web e vengono restituiti dal Web browser ogni volta che viene eseguito un postback. Poiché l'attributo name dei pulsanti di opzione nel GridView viene reso SuppliersGroup, quando la pagina Web viene inviata nuovamente al server Web, il browser invierà SuppliersGroup=valueOfSelectedRadioButton (insieme agli altri campi del modulo). È quindi possibile accedere a queste informazioni dalla Request.Form proprietà utilizzando : Request.Form["SuppliersGroup"].

Poiché dobbiamo determinare l'indice del pulsante di opzione selezionato non solo nel gestore eventi RowCreated, ma anche nei gestori eventi per i controlli Web Button Click, aggiungiamo una proprietà SuppliersSelectedIndex alla classe code-behind che restituisce -1 se nessun pulsante di opzione è stato selezionato e l'indice selezionato se uno dei pulsanti di opzione è stato scelto.

private int SuppliersSelectedIndex
{
    get
    {
        if (string.IsNullOrEmpty(Request.Form["SuppliersGroup"]))
            return -1;
        else
            return Convert.ToInt32(Request.Form["SuppliersGroup"]);
    }
}

Con questa proprietà aggiunta, sappiamo di dover inserire il markup checked="checked" nel gestore dell'evento RowCreated quando SuppliersSelectedIndex è uguale a e.Row.RowIndex. Aggiornare il gestore eventi per includere questa logica:

protected void Suppliers_RowCreated(object sender, GridViewRowEventArgs e)
{
    if (e.Row.RowType == DataControlRowType.DataRow)
    {
        // Grab a reference to the Literal control
        Literal output = (Literal)e.Row.FindControl("RadioButtonMarkup");
        // Output the markup except for the "checked" attribute
        output.Text = string.Format(
            @"<input type="radio" name="SuppliersGroup" " +
            @"id="RowSelector{0}" value="{0}"", e.Row.RowIndex);
        // See if we need to add the "checked" attribute
        if (SuppliersSelectedIndex == e.Row.RowIndex)
            output.Text += @" checked="checked"";
        // Add the closing tag
        output.Text += " />";
    }
}

Con questa modifica, il pulsante di opzione selezionato rimane selezionato dopo un postback. Ora che è possibile specificare il pulsante di opzione selezionato, è possibile modificare il comportamento in modo che quando la pagina è stata visitata per la prima volta, è stato selezionato il pulsante di opzione della prima riga di GridView (invece di non avere pulsanti di opzione selezionati per impostazione predefinita, ovvero il comportamento corrente). Per fare in modo che il primo pulsante di opzione sia selezionato per impostazione predefinita, è sufficiente modificare l'istruzione if (SuppliersSelectedIndex == e.Row.RowIndex) nel modo seguente: if (SuppliersSelectedIndex == e.Row.RowIndex || (!Page.IsPostBack && e.Row.RowIndex == 0)).

A questo punto, abbiamo aggiunto una colonna di pulsanti di opzione raggruppati a GridView che consente di selezionare e ricordare una singola riga di GridView tra i postback. I nostri passaggi successivi sono la visualizzazione dei prodotti forniti dal fornitore selezionato. Nel passaggio 4 verrà illustrato come reindirizzare l'utente a un'altra pagina, inviando lungo l'oggetto selezionato SupplierID. Nel passaggio 5 verrà illustrato come visualizzare i prodotti del fornitore selezionato in un controllo GridView nella stessa pagina.

Annotazioni

Invece di usare il TemplateField (che è l'argomento principale di questo lungo passaggio 3), è possibile creare una classe personalizzata DataControlField che rende l'interfaccia utente e le funzionalità appropriate. La DataControlField classe è la classe base da cui derivano i campi BoundField, CheckBoxField, TemplateField e altri campi GridView e DetailsView predefiniti. La creazione di una classe personalizzata DataControlField significa che la colonna dei pulsanti di opzione può essere aggiunta solo usando la sintassi dichiarativa e renderebbe anche più semplice replicare le funzionalità in altre pagine Web e altre applicazioni Web.

Se hai mai creato controlli personalizzati e compilati in ASP.NET, sai che questa operazione richiede una quantità notevole di lavoro preliminare e comporta una serie di sottigliezze e casi particolari che devono essere gestiti con attenzione. Di conseguenza, rinunceremo all'implementazione di una colonna di pulsanti di opzione come classe personalizzata DataControlField per ora e ci atteniamo all'opzione TemplateField. Forse si avrà la possibilità di esplorare la creazione, l'uso e la distribuzione di classi personalizzate DataControlField in un'esercitazione futura.

Passaggio 4: Visualizzazione dei prodotti dei fornitori selezionati in una pagina separata

Dopo che l'utente ha selezionato una riga GridView, è necessario visualizzare i prodotti del fornitore selezionato. In alcune circostanze, potremmo voler visualizzare questi prodotti in una pagina separata, in altri potrebbe essere preferibile farlo nella stessa pagina. Prima di tutto esaminiamo come visualizzare i prodotti in una pagina separata; nel passaggio 5 si esaminerà come aggiungere un controllo GridView a RadioButtonField.aspx per visualizzare i prodotti del fornitore selezionato.

Attualmente sono disponibili due controlli Web Button nella pagina ListProducts e SendToProducts. Quando si fa clic sul SendToProducts pulsante, si vuole inviare l'utente a ~/Filtering/ProductsForSupplierDetails.aspx. Questa pagina è stata creata nel tutorial Filtro Master/Dettaglio attraverso due pagine e visualizza i prodotti per il fornitore, il cui SupplierID viene passato attraverso il campo della querystring denominato SupplierID.

Per fornire questa funzionalità, creare un gestore eventi per l'evento SendToProducts Button s Click . Nel passaggio 3 è stata aggiunta la proprietà SuppliersSelectedIndex, che restituisce l'indice della riga, il cui pulsante di opzione è selezionato. Il corrispondente SupplierID può essere recuperato dalla raccolta DataKeys di GridView e l'utente può quindi essere inviato a ~/Filtering/ProductsForSupplierDetails.aspx?SupplierID=SupplierID usando Response.Redirect("url").

protected void SendToProducts_Click(object sender, EventArgs e)
{
    // Send the user to ~/Filtering/ProductsForSupplierDetails.aspx
    int supplierID = 
        Convert.ToInt32(Suppliers.DataKeys[SuppliersSelectedIndex].Value);
    Response.Redirect(
        "~/Filtering/ProductsForSupplierDetails.aspx?SupplierID=" 
        + supplierID);
    }
}

Questo codice funziona in modo meraviglioso, purché uno dei pulsanti di opzione sia selezionato da GridView. Se inizialmente GridView non ha pulsanti di opzione selezionati e l'utente fa clic sul pulsante SendToProducts, SuppliersSelectedIndex sarà -1, che causerà un'eccezione perché -1 non è compreso nell'intervallo di indici della raccolta DataKeys. Questo non è un problema, tuttavia, se si è deciso di aggiornare il gestore eventi RowCreated come descritto nel passaggio 3, in modo da avere inizialmente selezionato il primo pulsante di opzione nel GridView.

Per accogliere un valore di SuppliersSelectedIndex, aggiungere alla pagina, sopra il GridView, un controllo Web di tipo Etichetta. Imposta la proprietà ID a ChooseSupplierMsg, la proprietà CssClass a Warning, le proprietà EnableViewState e Visible a false, e la proprietà Text a Scegliere un fornitore dalla griglia. La classe Warning CSS visualizza il testo in un carattere rosso, corsivo, grassetto, grande ed è definito in Styles.css. Impostando le proprietà EnableViewState e Visible su false, l'etichetta viene renderizzata solo nei postback in cui la proprietà Visible del controllo è impostata a livello di codice su true.

Aggiungere un controllo Web Label sopra la GridView

Figura 13: Aggiungere un controllo Web Label sopra il GridView (fare clic per visualizzare l'immagine a grandezza naturale)

Successivamente, aumentare il Click gestore eventi per visualizzare l'etichetta ChooseSupplierMsg se SuppliersSelectedIndex è minore di zero e reindirizzare l'utente a ~/Filtering/ProductsForSupplierDetails.aspx?SupplierID=SupplierID in caso contrario.

protected void SendToProducts_Click(object sender, EventArgs e)
{
    // make sure one of the radio buttons has been selected
    if (SuppliersSelectedIndex < 0)
        ChooseSupplierMsg.Visible = true;
    else
    {
        // Send the user to ~/Filtering/ProductsForSupplierDetails.aspx
        int supplierID = 
            Convert.ToInt32(Suppliers.DataKeys[SuppliersSelectedIndex].Value);
        Response.Redirect(
            "~/Filtering/ProductsForSupplierDetails.aspx?SupplierID=" 
            + supplierID);
    }
}

Visitare la pagina in un browser e fare clic sul SendToProducts pulsante prima di selezionare un fornitore da GridView. Come illustrato nella figura 14, viene visualizzata l'etichetta ChooseSupplierMsg . Selezionare quindi un fornitore e fare clic sul SendToProducts pulsante . Verrà visualizzata una pagina che elenca i prodotti forniti dal fornitore selezionato. La figura 15 mostra la ProductsForSupplierDetails.aspx pagina in cui è stato selezionato il fornitore Bigfoot Breweries.

L'etichetta ChooseSupplierMsg viene visualizzata se non è selezionato alcun fornitore

Figura 14: L'etichetta ChooseSupplierMsg viene visualizzata se non è selezionato nessun fornitore (fare clic per visualizzare l'immagine a dimensione intera)

I prodotti dei fornitori selezionati vengono visualizzati in ProductsForSupplierDetails.aspx

Figura 15: I prodotti del fornitore selezionati sono visualizzati in ProductsForSupplierDetails.aspx (fare clic per visualizzare l'immagine a dimensione intera)

Passaggio 5: Visualizzazione dei prodotti dei fornitori selezionati nella stessa pagina

Nel passaggio 4 è stato illustrato come inviare l'utente a un'altra pagina Web per visualizzare i prodotti del fornitore selezionato. In alternativa, i prodotti dei fornitori selezionati possono essere visualizzati nella stessa pagina. Per illustrare questo esempio, aggiungeremo un altro GridView a RadioButtonField.aspx per visualizzare i prodotti del fornitore selezionato.

Poiché vogliamo che il GridView dei prodotti venga visualizzato solo dopo che è stato selezionato un fornitore, aggiungere un controllo Web Panel sotto il Suppliers GridView, impostando la sua proprietà ID su ProductsBySupplierPanel e la proprietà Visible su false. Aggiungi il testo 'Products for the Selected Supplier' (Prodotti per il fornitore selezionato) all'interno del pannello, seguito da un controllo GridView denominato ProductsBySupplier. Dallo smart tag di GridView scegliere di associarlo a un nuovo ObjectDataSource denominato ProductsBySupplierDataSource.

Associare il GridView di ProductsBySupplier a un nuovo ObjectDataSource

Figura 16: Associare ProductsBySupplier GridView a un nuovo oggettoDataSource (fare clic per visualizzare l'immagine a dimensione intera)

Configurare quindi ObjectDataSource per l'uso della ProductsBLL classe . Poiché si vogliono recuperare solo i prodotti forniti dal fornitore selezionato, specificare che ObjectDataSource deve richiamare il GetProductsBySupplierID(supplierID) metodo per recuperare i dati. Selezionare (Nessuno) negli elenchi a discesa nelle schede UPDATE, INSERT e DELETE.

Configurare ObjectDataSource per l'uso del metodo GetProductsBySupplierID(supplierID)

Figura 17: Configurare ObjectDataSource per l'uso del metodo (GetProductsBySupplierID(supplierID) a dimensione intera)

Impostare elenchi di Drop-Down su (Nessuno) nelle schede UPDATE, INSERT e DELETE

Figura 18: Impostare gli elenchi di Drop-Down su (Nessuno) nelle schede UPDATE, INSERT e DELETE (fare clic per visualizzare l'immagine a dimensione intera)

Dopo aver configurato le schede SELECT, UPDATE, INSERT e DELETE, fare clic su Avanti. Poiché il GetProductsBySupplierID(supplierID) metodo si aspetta un parametro di input, la procedura guidata Crea origine dati ci invita a specificare l'origine del valore del parametro.

Qui sono disponibili due opzioni per specificare l'origine del valore del parametro. È possibile utilizzare l'oggetto Parameter predefinito e assegnare a livello di codice il valore della SuppliersSelectedIndex proprietà alla proprietà Parameter s DefaultValue nel gestore eventi di Selecting ObjectDataSource. Fare riferimento all'esercitazione Impostazione dei valori dei parametri di ObjectDataSource a livello di codice per rinfrescare la memoria sull'assegnazione di valori ai parametri dell'ObjectDataSource.

In alternativa, è possibile usare ControlParameter e fare riferimento alla proprietà di GridView (Suppliers) nella SelectedValue figura 19. La proprietà SelectedValue di GridView restituisce il valore DataKey corrispondente alla proprietà SelectedIndex. Per consentire il funzionamento di questa opzione, è necessario impostare a livello di codice la proprietà GridView sulla SelectedIndex riga selezionata quando si fa clic sul ListProducts pulsante. Come vantaggio aggiuntivo, impostando il SelectedIndex, il record selezionato assumerà lo stile SelectedRowStyle definito nel Tema DataWebControls (uno sfondo giallo).

Usare un oggetto ControlParameter per specificare l'oggetto SelectedValue di GridView come origine del parametro

Figura 19: Usare un ControlParameter per specificare SelectedValue di GridView come origine del parametro (fare clic per visualizzare l'immagine a schermo intero)

Al termine della procedura guidata, Visual Studio aggiungerà automaticamente campi per i campi dati del prodotto. Rimuovi tutti i BoundFields tranne ProductName, CategoryName e UnitPrice, e modifica le proprietà HeaderText in Product, Category e Price. Configurare BoundField UnitPrice in modo che il relativo valore sia formattato come valuta. Dopo aver apportato queste modifiche, il markup dichiarativo di Panel, GridView e ObjectDataSource dovrebbe essere simile al seguente:

<asp:Panel runat="server" ID="ProductsBySupplierPanel" Visible="False">
    <h3>
        Products for the Selected Supplier</h3>
    <p>
        <asp:GridView ID="ProductsBySupplier" runat="server" 
            AutoGenerateColumns="False" DataKeyNames="ProductID"
            DataSourceID="ProductsBySupplierDataSource" EnableViewState="False">
            <Columns>
                <asp:BoundField DataField="ProductName" HeaderText="Product" 
                    SortExpression="ProductName" />
                <asp:BoundField DataField="CategoryName" HeaderText="Category" 
                    ReadOnly="True" SortExpression="CategoryName" />
                <asp:BoundField DataField="UnitPrice" DataFormatString="{0:c}" 
                    HeaderText="Price" HtmlEncode="False" 
                    SortExpression="UnitPrice" />
            </Columns>
        </asp:GridView>
        <asp:ObjectDataSource ID="ProductsBySupplierDataSource" runat="server" 
            OldValuesParameterFormatString="original_{0}"
            SelectMethod="GetProductsBySupplierID" TypeName="ProductsBLL">
            <SelectParameters>
                <asp:ControlParameter ControlID="Suppliers" Name="supplierID" 
                    PropertyName="SelectedValue" Type="Int32" />
            </SelectParameters>
        </asp:ObjectDataSource>
    </p>
</asp:Panel>

Per completare questo esercizio, è necessario impostare la proprietà gridView su SelectedIndex e la SelectedSuppliersIndex proprietà Panel s ProductsBySupplierPanel su Visible quando si fa clic sul true pulsante.ListProducts Per farlo, creare un gestore eventi per l'evento ListProducts del controllo Web Button Click e aggiungere il codice seguente:

protected void ListProducts_Click(object sender, EventArgs e)
{
    // make sure one of the radio buttons has been selected
    if (SuppliersSelectedIndex < 0)
    {
        ChooseSupplierMsg.Visible = true;
        ProductsBySupplierPanel.Visible = false;
    }
    else
    {
        // Set the GridView's SelectedIndex
        Suppliers.SelectedIndex = SuppliersSelectedIndex;
        // Show the ProductsBySupplierPanel panel
        ProductsBySupplierPanel.Visible = true;
    }
}

Se un fornitore non è stato selezionato da GridView, l'etichetta ChooseSupplierMsg viene visualizzata e il ProductsBySupplierPanel pannello nascosto. In caso contrario, se è stato selezionato un fornitore, ProductsBySupplierPanel viene visualizzato e la proprietà del GridView viene SelectedIndex aggiornata.

La figura 20 mostra i risultati dopo che il fornitore Bigfoot Breweries è stato selezionato e il pulsante Mostra prodotti nella pagina è stato selezionato.

I prodotti forniti da Bigfoot Breweries sono elencati nella stessa pagina

Figura 20: I prodotti forniti da Bigfoot Breweries sono elencati nella stessa pagina (fare clic per visualizzare l'immagine a dimensione intera)

Riassunto

Come discusso nell'esercitazione Master/Detail Using a Selectable Master GridView with a Details DetailView, i record possono essere selezionati da un controllo GridView usando un campo CommandField la cui ShowSelectButton proprietà è impostata su true. CommandField visualizza i suoi pulsanti come normali pulsanti a pressione, collegamenti o immagini. Un'interfaccia utente alternativa per la selezione di righe consiste nel fornire un pulsante di opzione o una casella di controllo in ogni riga gridView. In questa esercitazione è stato esaminato come aggiungere una colonna di pulsanti di opzione.

Sfortunatamente, l'aggiunta di una colonna di pulsanti di opzione non è facile o semplice come ci si potrebbe aspettare. Non esiste alcun oggetto RadioButtonField predefinito che può essere aggiunto al clic di un pulsante e l'uso del controllo Web RadioButton all'interno di un oggetto TemplateField introduce un proprio set di problemi. Alla fine, per fornire tale interfaccia è necessario creare una classe personalizzata DataControlField o ricorrere all'inserimento del codice HTML appropriato in un oggetto TemplateField durante l'evento RowCreated .

Dopo aver esaminato come aggiungere una colonna di pulsanti di opzione, concentriamoci su come aggiungere una colonna di caselle di controllo. Con una colonna di caselle di controllo, un utente può selezionare una o più righe gridView e quindi eseguire alcune operazioni su tutte le righe selezionate( ad esempio selezionando un set di messaggi di posta elettronica da un client di posta elettronica basato sul Web e quindi scegliendo di eliminare tutti i messaggi di posta elettronica selezionati). Nell'esercitazione successiva verrà illustrato come aggiungere una colonna di questo tipo.

Buon programmatori!

Informazioni sull'autore

Scott Mitchell, autore di sette libri ASP/ASP.NET e fondatore di 4GuysFromRolla.com, ha lavorato 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 a mitchell@4GuysFromRolla.com.

Grazie speciale a

Questa serie di esercitazioni è stata esaminata da molti revisori competenti. Il revisore principale per questo tutorial è stato David Suru. Si è interessati a esaminare i prossimi articoli MSDN? In tal caso, mandami un messaggio a mitchell@4GuysFromRolla.com.