Dela via


Lägga till en kolumn i GridView med radioknappar (VB)

av Scott Mitchell

Ladda ned PDF

I den här handledningen tittar vi på hur du lägger till en kolumn med alternativknappar i en GridView-kontroll för att ge användaren ett mer intuitivt sätt att välja en enda rad i GridView-kontrollen.

Inledning

GridView-kontrollen erbjuder en hel del inbyggda funktioner. Den innehåller ett antal olika fält för att visa text, bilder, hyperlänkar och knappar. Den stöder mallar för ytterligare anpassning. Med några få musklickningar går det att skapa en GridView där varje rad kan väljas via en knapp eller för att aktivera redigerings- eller borttagningsfunktioner. Trots den mängd funktioner som tillhandahålls finns det ofta situationer där ytterligare funktioner som inte stöds måste läggas till. I den här självstudien och de kommande två ska vi undersöka hur du kan förbättra GridView-funktionerna så att de innehåller ytterligare funktioner.

Den här handledningen och nästa fokuserar på att förbättra radvalsprocessen. Som vi har gått igenom i Master/Detail Using a Selectable Master GridView with a Details DetailView kan vi lägga till ett CommandField i GridView som innehåller en knapp för att välja. Vid klick sker en postback och egenskapen GridView SelectedIndex uppdateras till indexet för raden vars välj-knapp har klickats. I tutorialen Master/Detail Using a Selectable Master GridView with a Details DetailView såg vi hur man använder den här funktionen för att visa detaljer för den valda GridView-raden.

Även om knappen Välj fungerar i många situationer kanske den inte fungerar lika bra för andra. I stället för att använda en knapp används ofta två andra användargränssnittselement för val: alternativknappen och kryssrutan. Vi kan utöka GridView så att varje rad i stället för en Select-knapp innehåller en alternativknapp eller kryssruta. I scenarier där användaren bara kan välja en av GridView-posterna kan radioknappen föredras framför knappen Välj. I situationer där användaren potentiellt kan välja flera poster, till exempel i ett webbaserat e-postprogram där en användare kanske vill markera flera meddelanden för att ta bort, erbjuder kryssrutan funktioner som inte är tillgängliga från användargränssnitten Välj-knapp eller alternativknapp.

I den här handledningen tittar vi på hur du lägger till en kolumn med alternativknappar i GridView. I självstudien fortsätter vi med kryssrutor.

Steg 1: Skapa och förbättra GridView-webbsidorna

Innan vi börjar förbättra GridView så att den innehåller en kolumn med radioknappar ska vi först ta en stund och skapa ASP.NET-sidorna i vårt webbplatsprojekt som vi behöver för den här självstudien och de två följande. Börja med att lägga till en ny mapp med namnet EnhancedGridView. Lägg sedan till följande ASP.NET sidor i mappen och se till att associera varje sida med Site.master huvudsidan:

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

Lägg till ASP.NET-sidorna för SqlDataSource-Related-tutorials

Bild 1: Lägg till ASP.NET-sidorna för SqlDataSource-Related-tutorials

Precis som i de andra mapparna kommer Default.aspx i EnhancedGridView-mappen att lista självstudierna i dess avsnitt. Kom ihåg att SectionLevelTutorialListing.ascx användarkontrollen innehåller den här funktionen. Lägg därför till den här användarkontrollen genom att Default.aspx dra den från Solution Explorer till sidans designvy.

Lägg till sectionLevelTutorialListing.ascx-användarkontrollen i Default.aspx

Bild 2: Lägg till SectionLevelTutorialListing.ascx användarkontrollen Default.aspx i (Klicka om du vill visa en bild i full storlek)

Slutligen lägger du till dessa fyra sidor som poster i Web.sitemap filen. Mer specifikt, lägg till följande markering efter att använda SqlDataSource-kontrollen <siteMapNode>:

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

Efter att du har uppdaterat Web.sitemap, ta en stund att besöka självstudiewebbplatsen via en webbläsare. Menyn till vänster innehåller nu alternativ för redigering, infogning och borttagning av handledningar.

Webbplatskartan innehåller nu poster för att förbättra GridView-självstudierna

Bild 3: Webbplatskartan inkluderar nu poster för handledningar som förbättrar GridView

Steg 2: Visa leverantörerna i en GridView

I denna handledning ska vi bygga en GridView som listar leverantörer från USA, där varje GridView-rad tillhandahåller en radioknapp. När du har valt en leverantör via radioknappen kan användaren visa leverantörens produkter genom att klicka på en knapp. Även om den här uppgiften kan låta trivial, finns det ett antal subtiliteter som gör det särskilt knepigt. Innan vi fördjupar oss i dessa subtiliteter ska vi först få en GridView-lista över leverantörerna.

Börja med att RadioButtonField.aspx öppna sidan i EnhancedGridView mappen genom att dra en GridView från verktygslådan till designern. Ange GridView s ID till Suppliers och välj sedan att skapa en ny datakälla från den smarta taggen. Mer specifikt skapar du en ObjectDataSource med namnet SuppliersDataSource som hämtar dess data från SuppliersBLL objektet.

Skapa en ny ObjectDataSource med namnet SuppliersDataSource

Bild 4: Skapa en ny ObjectDataSource med namnet SuppliersDataSource (Klicka om du vill visa en bild i full storlek)

Skärmbild av fönstret Konfigurera datakälla – LeverantörerDataKälla med listrutan affärsobjekt öppen. SuppliersBLL har valts och knappen Nästa är markerad.

Bild 5: Konfigurera ObjectDataSource att använda SuppliersBLL klassen (Klicka om du vill visa en bild i full storlek)

Eftersom vi bara vill lista dessa leverantörer i USA väljer du GetSuppliersByCountry(country) metoden i listrutan på fliken SELECT.

Skärmbild av fönstret Konfigurera datakälla – leverantörerDataKälla på fliken SELECT med listrutan metod öppen. Metodalternativet GetSupplierByCountry är markerat och knappen Nästa är markerad.

Bild 6: Konfigurera ObjectDataSource att använda SuppliersBLL klassen (Klicka om du vill visa en bild i full storlek)

På fliken UPPDATERA väljer du alternativet (Ingen) och klickar på Nästa.

Skärmbild av fönstret Konfigurera datakälla – leverantörerDataKälla på fliken UPPDATERA med listrutan metod öppen. Metodalternativet (Ingen) är markerat och knappen Nästa är markerad.

Bild 7: Konfigurera ObjectDataSource att använda SuppliersBLL klassen (Klicka om du vill visa en bild i full storlek)

GetSuppliersByCountry(country) Eftersom metoden accepterar en parameter frågar guiden Konfigurera datakälla oss om källan till parametern. Om du vill ange ett hårdkodat värde ( USA i det här exemplet) lämnar du listrutan Parameterkälla inställd på Ingen och anger standardvärdet i textrutan. Klicka på Slutför för att slutföra guiden.

Använd USA som standardvärde för landsparametern

Bild 8: Använd USA som standardvärde för parametern country (Klicka om du vill visa en bild i full storlek)

När du har slutfört guiden innehåller GridView ett BoundField för vart och ett av leverantörsdatafälten. Ta bort alla utom CompanyName, City, och Country BoundFields och byt namn på CompanyName BoundFields HeaderText-egenskapen till Leverantör. När du har gjort det bör deklarativ syntax för GridView och ObjectDataSource se ut ungefär så här.

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

I den här självstudien låter vi användaren visa den valda leverantörens produkter på samma sida som leverantörslistan eller på en annan sida. Lägg till två knappwebbkontroller på sidan för att hantera detta. Jag har ställt in egenskaperna för dessa två knappar, ID, till ListProducts och SendToProducts, med tanken att när ListProducts klickas kommer en postback att ske och den valda leverantörens produkter kommer att visas på samma sida. Men när SendToProducts klickas, kommer användaren att skickas till en annan sida som listar produkterna.

Bild 9 visar Suppliers GridView och de två knappwebbkontrollerna när de visas via en webbläsare.

Dessa leverantörer från USA har sina namn, orter och landsinformation listade

Bild 9: Dessa leverantörer från USA har sitt namn, sin stad och sin landsinformation listad (Klicka om du vill visa en bild i full storlek)

Steg 3: Lägga till en kolumn med alternativknappar

Suppliers Nu har GridView tre BoundFields som visar företagets namn, stad och land för varje leverantör i USA. Den saknar dock fortfarande en kolumn med alternativknappar. Tyvärr innehåller GridView inte en inbyggd "RadioButtonField", annars skulle vi kunna lägga till den i GridView och vara klara. I stället kan vi lägga till ett TemplateField och konfigurera dess ItemTemplate för att visa en radioknapp, vilket ger en radioknapp för varje GridView-rad.

Inledningsvis kan vi anta att det önskade användargränssnittet kan implementeras genom att lägga till en RadioButton-webbkontroll i ItemTemplate mallfältet. Även om detta verkligen kommer att lägga till en enda alternativknapp till varje rad i GridView, kan alternativknapparna inte grupperas och är därför inte exklusiva för varandra. En slutanvändare har möjlighet att välja flera radioknappar samtidigt i GridView.

Trots att användning av en TemplateField med RadioButton Web-kontroller inte erbjuder de funktioner vi behöver, bör vi ändå implementera den här metoden, eftersom det är viktigt att undersöka varför de resulterande alternativknapparna inte är grupperade. Börja med att lägga till ett TemplateField i Suppliers GridView, vilket gör det till det vänstra fältet. Klicka sedan på länken Redigera mallar från GridViews smarta tagg och dra en RadioButton Web-kontroll från verktygslådan till TemplateFields ItemTemplate (se bild 10). Ange RadioButtons egenskap ID till RowSelector och egenskap GroupName till SuppliersGroup.

Lägg till en RadioButton-webbkontroll i ItemTemplate

Bild 10: Lägg till en RadioButton-webbkontroll i ItemTemplate (Klicka om du vill visa en bild i full storlek)

När du har gjort dessa tillägg via designern bör din GridView-markering se ut ungefär så här:

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

RadioButton s GroupName-egenskapen används för att gruppera en serie alternativknappar. Alla RadioButton-kontroller med samma GroupName värde betraktas som grupperade. Endast en alternativknapp kan väljas från en grupp i taget. Egenskapen GroupName anger värdet för den renderade alternativknappens attribut name. Webbläsaren undersöker radioknappsattributen name för att fastställa radioknappsgrupperingarna.

Med RadioButton-webbkontrollen tillagd till ItemTemplate, besöker du sidan via en webbläsare och klickar på alternativknapparna i rutnätets rader. Observera hur alternativknapparna inte är grupperade, vilket gör det möjligt att välja alla rader, som bild 11 visar.

GridViews radioknappar är inte grupperade

Bild 11: GridViews alternativknappar är inte grupperade (klicka om du vill visa en bild i full storlek)

Anledningen till att alternativknapparna inte är grupperade är att deras renderade name-attribut är olika, trots att de har samma GroupName-egenskap. Om du vill se dessa skillnader gör du en vy/källa från webbläsaren och undersöker alternativknappsmarkeringen:

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

Observera att både attributen name och id inte är de exakta värdena som anges i fönstret Egenskaper, utan läggs till med ett antal andra ID värden. De ytterligare ID värden som läggs till framför de renderade id och name attributen är ID av alternativknapparnas överordnade kontroller som styr GridViewRowID, GridViews ID, innehållskontrollens ID och webbformulärets ID. Dessa ID läggs till så att varje renderad webbkontroll i GridView har unika id värden och name värden.

Varje renderad kontroll behöver en annan name och id eftersom det är så webbläsaren unikt identifierar varje kontroll på klientsidan och hur den identifierar för webbservern vilken åtgärd eller ändring som har inträffat vid postback. Anta till exempel att vi ville köra kod på serversidan när ett Kontrollerat tillstånd för RadioButton ändrades. Vi skulle kunna åstadkomma detta genom att ange egenskapen för RadioButton till AutoPostBack och skapa en händelsehanterare för True-händelsen. Men om de renderade name-värdena och id-värdena för alla alternativknappar var desamma, kunde vi inte avgöra vilken specifik alternativknapp som klickades när sidan skickades tillbaka.

Kort sagt kan vi inte skapa en kolumn med radioknappar i en GridView med hjälp av RadioButton-webbkontrollen. I stället måste vi använda ganska ålderdomliga tekniker för att säkerställa att rätt markering matas in i varje GridView-rad.

Anmärkning

Precis som RadioButton Web-kontrollen innehåller html-kontrollen för alternativknappen, när den läggs till i en mall, det unika name attributet, vilket gör att alternativknapparna i rutnätet inte är grupperade. Om du inte är bekant med HTML-kontroller kan du ignorera den här anteckningen eftersom HTML-kontroller sällan används, särskilt i ASP.NET 2.0. Men om du är intresserad av att lära dig mer kan du läsa K. Scott Allens blogginlägg Webbkontroller och HTML-kontroller.

Använda en Literal Control för att mata in radioknappsmärkning

För att kunna gruppera alla alternativknappar i GridView korrekt måste vi manuellt mata in alternativknapparnas markering i ItemTemplate. Varje alternativknapp behöver samma name attribut, men bör ha ett unikt id attribut (om vi vill komma åt en alternativknapp via skript på klientsidan). När en användare har valt en alternativknapp och lagt tillbaka sidan skickar webbläsaren tillbaka värdet för det valda alternativknappsattributet value . Därför behöver varje alternativknapp ett unikt attribut value. Slutligen måste vi vid postback se till att lägga till attributet checked på den radioknapp som har valts, annars kommer alternativknapparna att återgå till standardtillståndet (alla omarkerade) när användaren har gjort en markering och skickar tillbaka.

Det finns två metoder som kan användas för att mata in markering på låg nivå i en mall. En är att göra en blandning av markering och anrop till formateringsmetoder som definierats i klassen code-behind. Den här tekniken diskuterades först i självstudien Använda TemplateFields i GridView-kontrollen. I vårt fall kan det se ut ungefär så här:

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

Här skulle GetUniqueRadioButton och GetRadioButtonValue vara metoder definierade i klassen code-behind som returnerade lämpliga attributvärden för id och value för varje alternativknapp. Den här metoden fungerar bra för att tilldela attributen id och value , men misslyckas när du behöver ange checked attributvärdet eftersom syntaxen för databindning endast körs när data först är bundna till GridView. Om tillståndsvisning är aktiverad för GridView, utlöses formateringsmetoderna därför endast när sidan läses in första gången (eller när GridView explicitt återkopplas till datakällan), och därför kommer funktionen som ställer in checked-attributet inte att anropas vid postback. Det är ett ganska subtilt problem och lite utanför omfattningen av den här artikeln, så jag lämnar det på detta. Jag rekommenderar dock att du försöker använda ovanstående metod och arbeta igenom den till den punkt där du kommer att fastna. Även om en sådan övning inte kommer närmare en fungerande version, kommer den att bidra till en djupare förståelse av GridView och databindningslivscykeln.

Den andra metoden för att mata in anpassad markering på låg nivå i en mall och den metod som vi ska använda för den här självstudien är att lägga till en Literal-kontroll i mallen. I GridView s RowCreated eller RowDataBound händelsehanteraren kan literalkontrollen sedan användas programmatiskt och dess Text egenskap anges till den markering som ska genereras.

Börja med att ta bort RadioButton från TemplateField s ItemTemplateoch ersätt den med en Literal-kontroll. Ställ in kontrollen "Literal" ID till RadioButtonMarkup.

Lägg till en literalkontroll i ItemTemplate

Bild 12: Lägg till en literalkontroll i ItemTemplate (Klicka om du vill visa en bild i full storlek)

Skapa sedan en händelsehanterare för GridView-händelsen RowCreated . Händelsen RowCreated utlöses en gång för varje rad som läggs till, oavsett om data returneras till GridView eller inte. Det innebär att även vid en postback när data läses in igen från visningstillståndet RowCreated utlöses händelsen fortfarande och det är anledningen till att vi använder den i stället för RowDataBound (som utlöses endast när data uttryckligen är bundna till datawebbkontrollen).

I den här händelsehanteraren vill vi bara fortsätta om vi hanterar en datarad. För varje datarad vill vi programmässigt referera RadioButtonMarkup till literalkontrollen och ange dess Text egenskap till den markering som ska genereras. Som följande kod visar, skapar den emitterade markeringen en alternativknapp vars name-attribut är inställt på SuppliersGroup, vars id-attribut är inställt på RowSelectorX, där X är indexet för GridView-raden och vars value-attribut är inställt på indexet för GridView-raden.

Protected Sub Suppliers_RowCreated(sender As Object, e As GridViewRowEventArgs) _
    Handles Suppliers.RowCreated
    
    If e.Row.RowType = DataControlRowType.DataRow Then
        ' Grab a reference to the Literal control
        Dim output As Literal = _
            CType(e.Row.FindControl("RadioButtonMarkup"), Literal)
        ' 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)
    End If
End Sub

När en GridView-rad väljs och en postback inträffar, är vi intresserade av den valda leverantörens SupplierID. Därför kan man tro att värdet för varje alternativknapp ska vara det faktiska SupplierID (snarare än indexet för GridView-raden). Även om detta kan fungera under vissa omständigheter, skulle det vara en säkerhetsrisk att blint acceptera och bearbeta en SupplierID. Vårt GridView listar till exempel endast de leverantörerna i USA. Men om SupplierID skickas direkt från radioknappen, vad hindrar en busig användare från att manipulera SupplierID-värdet som skickas tillbaka vid postback? Genom att använda radindexet som value, och sedan hämta SupplierID vid postback från DataKeys-samlingen, kan vi se till att användaren endast använder ett av de SupplierID-värden som är associerade med en av GridView-raderna.

När du har lagt till den här händelsehanterarkoden tar det en minut att testa sidan i en webbläsare. Observera först att endast en alternativknapp i rutnätet kan väljas i taget. Men när du väljer en alternativknapp och klickar på en av knapparna sker en återkoppling och alla alternativknappar återgår till sitt ursprungliga tillstånd (det vill säga vid återkoppling är den valda alternativknappen inte längre markerad). För att åtgärda detta måste vi utöka RowCreated händelsehanteraren så att den inspekterar det valda alternativknappindexet som skickas från postback och lägger till checked="checked" attributet till den avgivna markeringen för radindexmatchningarna.

När en postback inträffar skickar webbläsaren tillbaka name och value för den markerade alternativknappen. Värdet kan hämtas programmatiskt med hjälp av Request.Form("name"). Egenskapen Request.Form innehåller en NameValueCollection som representerar formulärvariablerna. Formulärvariablerna är namn och värden för formulärfälten på webbsidan och skickas tillbaka av webbläsaren när en postback sker. Eftersom det renderade name attributet för alternativknapparna i GridView är SuppliersGroup, när webbsidan skickas tillbaka kommer webbläsaren att skicka SuppliersGroup=valueOfSelectedRadioButton tillbaka till webbservern (tillsammans med de andra formulärfälten). Den här informationen kan sedan nås från egenskapen Request.Form med hjälp av: Request.Form("SuppliersGroup").

Eftersom vi måste fastställa det valda alternativknappindexet, inte bara i RowCreated händelsehanteraren, utan i Click händelsehanterarna för knappwebbkontrollerna, ska vi lägga till en SuppliersSelectedIndex egenskap i klassen code-behind som returnerar -1 om ingen alternativknapp har valts och det valda indexet om någon av alternativknapparna har valts.

Private ReadOnly Property SuppliersSelectedIndex() As Integer
    Get
        If String.IsNullOrEmpty(Request.Form("SuppliersGroup")) Then
            Return -1
        Else
            Return Convert.ToInt32(Request.Form("SuppliersGroup"))
        End If
    End Get
End Property

När den här egenskapen har lagts till vet vi att lägga till checked="checked"-markeringen i RowCreated-händelsehanteraren när SuppliersSelectedIndex är lika med e.Row.RowIndex. Uppdatera händelsehanteraren så att den innehåller den här logiken:

Protected Sub Suppliers_RowCreated(sender As Object, e As GridViewRowEventArgs) _
    Handles Suppliers.RowCreated
    
    If e.Row.RowType = DataControlRowType.DataRow Then
        ' Grab a reference to the Literal control
        Dim output As Literal = _
            CType(e.Row.FindControl("RadioButtonMarkup"), Literal)
        ' 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 Then
            output.Text &= " checked="checked""
        End If
        ' Add the closing tag
        output.Text &= " />"
    End If
End Sub

Med den här ändringen förblir den valda alternativknappen markerad efter ett återanrop. Nu när vi har möjlighet att ange vilken alternativknapp som har valts kan vi ändra beteendet så att när sidan först besöktes valdes den första GridView-radens alternativknapp (i stället för att inga alternativknappar har valts som standard, vilket är det aktuella beteendet). Om du vill att den första alternativknappen ska väljas som standard ändrar du instruktionen If SuppliersSelectedIndex = e.Row.RowIndex Then till följande: If SuppliersSelectedIndex = e.Row.RowIndex OrElse (Not Page.IsPostBack AndAlso e.Row.RowIndex = 0) Then.

Nu har vi lagt till en kolumn med grupperade radioknappar i GridView som gör att en enda GridView-rad kan väljas och kommas ihåg mellan postbacks. Nästa steg är att visa de produkter som tillhandahålls av den valda leverantören. I steg 4 får vi se hur man omdirigerar användaren till en annan sida och skickar med den valda SupplierID. I steg 5 ser vi hur du visar den valda leverantörens produkter i en GridView på samma sida.

Anmärkning

I stället för att använda ett TemplateField (fokus för det här långa steg 3) kan vi skapa en anpassad DataControlField klass som renderar rätt användargränssnitt och funktionalitet. KlassenDataControlField är basklassen från vilken fälten BoundField, CheckBoxField, TemplateField och andra inbyggda GridView- och DetailsView-fält härleds. Att skapa en anpassad DataControlField-klass skulle innebära att kolumnen med radioknappar kan läggas till enbart med deklarativ syntax och dessutom göra det betydligt enklare att replikera funktionaliteten på andra webbsidor och webbapplikationer.

Om du någonsin har skapat anpassade, kompilerade kontroller i ASP.NET vet du dock att detta kräver en hel del benarbete och bär med sig en mängd subtiliteter och kantfall som måste hanteras noggrant. Därför avstår vi från att implementera en kolumn med radioknappar som en anpassad DataControlField klass för tillfället och håller oss till TemplateField-alternativet. Kanske får vi chansen att utforska att skapa, använda och distribuera anpassade DataControlField klasser i en framtida handledning!

Steg 4: Visa den valda leverantörens produkter på en separat sida

När användaren har valt en GridView-rad måste vi visa den valda leverantörens produkter. I vissa fall kanske vi vill visa dessa produkter på en separat sida, i andra kanske vi föredrar att göra det på samma sida. Låt oss först undersöka hur du visar produkterna på en separat sida; i steg 5 tittar vi på att lägga till en GridView för att RadioButtonField.aspx visa den valda leverantörens produkter.

För närvarande finns det två knappwebbkontroller på sidan ListProducts och SendToProducts. SendToProducts När knappen klickas vill vi skicka användaren till ~/Filtering/ProductsForSupplierDetails.aspx. Den här sidan skapades i självstudiekursen Master/Detail Filtering Across Two Pages (Huvud-/detaljfiltrering över två sidor) och visar produkterna för den leverantör vars SupplierID skickas via frågesträngsfältet med namnet SupplierID.

För att tillhandahålla den här funktionen, skapa en händelsehanterare för knappens SendToProducts-händelse Click. I steg 3, lade vi till SuppliersSelectedIndex-egenskapen, som returnerar indexet för raden vars radioknapp är vald. Motsvarande SupplierID kan hämtas från GridView-samlingen DataKeys och användaren kan sedan skickas till ~/Filtering/ProductsForSupplierDetails.aspx?SupplierID=SupplierID med hjälp av Response.Redirect("url").

Protected Sub SendToProducts_Click(sender As Object, e As EventArgs) _
    Handles SendToProducts.Click
    
    ' Send the user to ~/Filtering/ProductsForSupplierDetails.aspx
    Dim supplierID As Integer = _
        Convert.ToInt32(Suppliers.DataKeys(SuppliersSelectedIndex).Value)
    Response.Redirect( _
        "~/Filtering/ProductsForSupplierDetails.aspx?SupplierID=" & _
        supplierID)
End Sub

Den här koden fungerar underbart så länge en av alternativknapparna har valts i GridView. Om GridView till en början inte har några alternativknappar valda och användaren klickar på SendToProducts-knappen, kommer SuppliersSelectedIndex att bli -1, vilket gör att ett undantag genereras eftersom -1 ligger utanför indexintervallet för DataKeys-kollektionen. Detta är dock inte ett problem om du har valt att uppdatera RowCreated händelsehanteraren enligt beskrivningen i steg 3 för att den första radioknappen i GridView ska vara markerad från början.

Lägg till en etikettwebbkontroll på sidan ovanför GridView för att hantera värdet SuppliersSelectedIndex-1. Ange egenskapen ID till ChooseSupplierMsg, dess CssClass egenskap till Warning, dess EnableViewState och Visible egenskaper till False, och dess Text egenskap till Välj en leverantör från rutnätet. CSS-klassen Warning visar text i ett rött, kursivt, fetstilt, stort teckensnitt och definieras i Styles.css. Genom att ange EnableViewState och Visible egenskaperna till False, renderas inte etiketten förutom vid de postbacks där kontrollens Visible egenskap är programmatiskt inställd på True.

Lägg till en etikettwebbkontroll ovanför GridView

Bild 13: Lägg till en etikettwebbkontroll ovanför GridView (Klicka om du vill visa en bild i full storlek)

Utöka sedan Click händelsehanteraren för att visa ChooseSupplierMsg etiketten om SuppliersSelectedIndex är mindre än noll och omdirigera användaren till ~/Filtering/ProductsForSupplierDetails.aspx?SupplierID=SupplierID annars.

Protected Sub SendToProducts_Click(sender As Object, e As EventArgs) _
    Handles SendToProducts.Click
    
    ' make sure one of the radio buttons has been selected
    If SuppliersSelectedIndex < 0 Then
        ChooseSupplierMsg.Visible = True
    Else
        ' Send the user to ~/Filtering/ProductsForSupplierDetails.aspx
        Dim supplierID As Integer = _
            Convert.ToInt32(Suppliers.DataKeys(SuppliersSelectedIndex).Value)
        Response.Redirect( _
            "~/Filtering/ProductsForSupplierDetails.aspx?SupplierID=" & _
            supplierID)
    End If
End Sub

Besök sidan i en webbläsare och klicka på SendToProducts knappen innan du väljer en leverantör från GridView. Som bild 14 visar, visas etiketten ChooseSupplierMsg. Välj sedan en leverantör och klicka på SendToProducts knappen. Detta tar dig till en sida som listar de produkter som tillhandahålls av den valda leverantören. Bild 15 visar sidan ProductsForSupplierDetails.aspx när Bigfoot Breweries-leverantören valdes.

Etiketten ChooseSupplierMsg visas om ingen leverantör har valts

Bild 14: Etiketten ChooseSupplierMsg visas om ingen leverantör har valts (Klicka om du vill visa en bild i full storlek)

De valda leverantörernas produkter visas i ProductsForSupplierDetails.aspx

Bild 15: Den valda leverantörens produkter visas i ProductsForSupplierDetails.aspx (Klicka om du vill visa en bild i full storlek)

Steg 5: Visa den valda leverantörens produkter på samma sida

I steg 4 såg vi hur du skickar användaren till en annan webbsida för att visa den valda leverantörens produkter. Alternativt kan den valda leverantörens produkter visas på samma sida. För att illustrera detta lägger vi till ytterligare en GridView för att RadioButtonField.aspx visa den valda leverantörens produkter.

Eftersom vi bara vill att den här GridView-produkten ska visas när en leverantör har valts lägger du till en panelwebbkontroll under Suppliers GridView och ställer in dess ID till ProductsBySupplierPanel och dess Visible egenskap till False. I panelen lägger du till texten Produkter för den valda leverantören följt av en GridView med namnet ProductsBySupplier. Från GridViews smarta tagg väljer du att binda den till en ny ObjectDataSource med namnet ProductsBySupplierDataSource.

Binda ProductsBySupplier GridView till ett nytt ObjectDataSource

Bild 16: Binda ProductsBySupplier GridView till en ny ObjectDataSource (Klicka om du vill visa en bild i full storlek)

Konfigurera sedan ObjectDataSource så att klassen ProductsBLL används. Eftersom vi bara vill hämta de produkter som tillhandahålls av den valda leverantören anger du att ObjectDataSource ska anropa GetProductsBySupplierID(supplierID) metoden för att hämta sina data. Välj (Ingen) i listrutorna på flikarna UPDATE, INSERT och DELETE.

Konfigurera ObjectDataSource att använda metoden GetProductsBySupplierID(supplierID)

Bild 17: Konfigurera ObjectDataSource att använda GetProductsBySupplierID(supplierID) metoden (Klicka om du vill visa en bild i full storlek)

Ange Drop-Down-listorna till (Ingen) i flikarna UPDATE, INSERT och DELETE

Bild 18: Ange Drop-Down-listorna till (Ingen) i flikarna UPDATE, INSERT och DELETE (Klicka om du vill visa en bild i full storlek)

När du har konfigurerat flikarna SELECT, UPDATE, INSERT och DELETE klickar du på Nästa. GetProductsBySupplierID(supplierID) Eftersom metoden förväntar sig en indataparameter uppmanar guiden Skapa datakälla oss att ange källan för parameterns värde.

Vi har ett par alternativ här för att ange källan för parameterns värde. Vi kan använda standard-Parameter-objektet och programmatiskt tilldela egenskapen SuppliersSelectedIndex sitt värde till Parameter-objektets egenskap i ObjectDataSources händelsehanterare för DefaultValue. Gå tillbaka till självstudien Programmatically Setting the ObjectDataSource's Parameter Values för en uppfriskning om hur man tilldelar värden till ObjectDataSource-parametrarna programmatiskt.

Alternativt kan vi använda en ControlParameter och referera till Suppliers egenskapen GridView SelectedValue (se bild 19). Egenskapen GridView SelectedValue returnerar värdet DataKey som motsvarar egenskapen SelectedIndex. För att det här alternativet ska fungera måste vi programmatiskt ange GridView-egenskapen till SelectedIndex den valda raden när knappen ListProducts klickas. Genom att ange SelectedIndex, får den valda posten den SelectedRowStyle som definieras i temat DataWebControls (en gul bakgrund) som en extra fördel.

Använd en ControlParameter för att ange GridView s SelectedValue som parameterkälla

Bild 19: Använd en ControlParameter för att ange GridView s SelectedValue som parameterkälla (Klicka om du vill visa en bild i full storlek)

När du har slutfört guiden lägger Visual Studio automatiskt till fält för produktens datafält. Ta bort alla utom ProductName, CategoryNameoch UnitPrice BoundFields och ändra HeaderText egenskaperna till Produkt, Kategori och Pris. UnitPrice Konfigurera BoundField så att dess värde formateras som en valuta. När du har gjort dessa ändringar bör panelen, GridView och ObjectDataSources deklarativa markering se ut så här:

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

För att slutföra den här övningen, måste vi ange GridView s SelectedIndex egenskap till SelectedSuppliersIndex och panelens ProductsBySupplierPanelVisible egenskap till True när ListProducts-knappen klickas. För att åstadkomma detta skapar du en händelsehanterare för knappwebbkontrollens ListProducts-händelse och lägger till följande kod:

Protected Sub ListProducts_Click(sender As Object, e As EventArgs) _
    Handles ListProducts.Click
    
    ' make sure one of the radio buttons has been selected
    If SuppliersSelectedIndex < 0 Then
        ChooseSupplierMsg.Visible = True
        ProductsBySupplierPanel.Visible = False
    Else
        ' Set the GridView's SelectedIndex
        Suppliers.SelectedIndex = SuppliersSelectedIndex
        ' Show the ProductsBySupplierPanel panel
        ProductsBySupplierPanel.Visible = True
    End If
End Sub

Om ingen leverantör har valts från GridView, visas etiketten ChooseSupplierMsg och panelen döljs ProductsBySupplierPanel. Annars, om en leverantör har valts, visas ProductsBySupplierPanel och egenskapen för GridView SelectedIndex uppdateras.

Bild 20 visar resultatet efter att Bigfoot Breweries-leverantören har valts och knappen Visa produkter på sidan har klickats.

De produkter som levereras av Bigfoot Breweries är listade på samma sida

Bild 20: De produkter som levereras av Bigfoot Breweries visas på samma sida (Klicka om du vill visa en bild i full storlek)

Sammanfattning

Som beskrivs i självstudiekursen Master/Detail Using a Selectable Master GridView with a Details DetailView kan poster väljas från ett GridView med hjälp av ett Kommandofält vars ShowSelectButton egenskap är inställd på True. Men CommandField visar sina knappar antingen som vanliga push-knappar, länkar eller bilder. Ett alternativt användargränssnitt för radval är att ange en alternativknapp eller kryssruta i varje GridView-rad. I den här handledningen undersökte vi hur man lägger till en rad med alternativknappar.

Tyvärr är det inte så enkelt eller okomplicerat att lägga till en kolumn med alternativknappar som man skulle kunna förvänta sig. Det finns ingen inbyggd RadioButtonField som kan läggas till med ett klick på en knapp, och med hjälp av RadioButton-webbkontrollen i ett TemplateField introduceras en egen uppsättning problem. För att tillhandahålla ett sådant gränssnitt måste vi antingen skapa en anpassad DataControlField klass eller använda till att mata in lämplig HTML i ett TemplateField under RowCreated händelsen.

Efter att ha utforskat hur vi lägger till en kolumn med alternativknappar, låt oss fokusera på att lägga till en kolumn med kryssrutor. Med en kolumn med kryssrutor kan en användare välja en eller flera GridView-rader och sedan utföra vissa åtgärder på alla markerade rader (till exempel välja en uppsättning e-postmeddelanden från en webbaserad e-postklient och sedan välja att ta bort alla markerade e-postmeddelanden). I nästa handledning får vi se hur du lägger till en sådan kolumn.

Lycka till med programmerandet!

Om författaren

Scott Mitchell, författare till sju ASP/ASP.NET-böcker och grundare av 4GuysFromRolla.com, har arbetat med Microsofts webbtekniker sedan 1998. Scott arbetar som oberoende konsult, tränare och författare. Hans senaste bok är Sams Teach Yourself ASP.NET 2.0 på 24 timmar. Han kan nås på mitchell@4GuysFromRolla.com.

Särskilt tack till

Den här självstudieserien granskades av många användbara granskare. Ansvarig granskare för den här handledningen var David Suru. Vill du granska mina kommande MSDN-artiklar? Om så är fallet, hör av dig på mitchell@4GuysFromRolla.com.