Udostępnij za pomocą


Dodawanie kolumny przycisków radiowych do kontrolki GridView (C#)

Autor : Scott Mitchell

Pobierz plik PDF

W tym samouczku przedstawiono sposób dodawania kolumny przycisków radiowych do kontrolki GridView w celu zapewnienia użytkownikowi bardziej intuicyjnego sposobu wybierania pojedynczego wiersza kontrolki GridView.

Wprowadzenie

Kontrolka GridView oferuje wiele wbudowanych funkcji. Zawiera on wiele różnych pól do wyświetlania tekstu, obrazów, hiperlinków i przycisków. Obsługuje szablony do dalszego dostosowywania. Za pomocą kilku kliknięć myszy można tworzyć GridView, w którym można wybierać każdy wiersz za pomocą przycisku lub włączyć funkcje edycji i usuwania. Pomimo wielu udostępnionych funkcji często występują sytuacje, w których należy dodać dodatkowe, nieobsługiwane funkcje. W tym samouczku i w kolejnych dwóch omówimy sposób ulepszania funkcji GridView w celu uwzględnienia dodatkowych funkcji.

Ten i następny samouczek koncentrują się na ulepszaniu procesu selekcji wierszy. Jak omówiono w Master/Detail przy użyciu wersji Selectable Master GridView z kontrolką DetailsView, możemy dodać polecenie do GridView, które zawiera przycisk Wybierz. Po kliknięciu zostanie wyświetlony komunikat zwrotny i właściwość GridView SelectedIndex zostanie zaktualizowana do indeksu wiersza, którego przycisk Wybierz został kliknięty. W samouczku Master/Detail Using a Selectable Master GridView with a Details DetailView pokazano, jak używać tej funkcji do wyświetlania szczegółów dla wybranego wiersza GridView.

Przycisk Wybierz działa w wielu sytuacjach, ale może nie działać również w przypadku innych osób. Zamiast używać przycisku, dwa inne elementy interfejsu użytkownika są często używane do zaznaczenia: przycisk radiowy i pole wyboru. Możemy rozszerzyć kontrolkę GridView, aby zamiast przycisku Wybierz każdy wiersz zawierał przycisk radiowy lub pole wyboru. W scenariuszach, w których użytkownik może wybrać tylko jeden z rekordów GridView, przycisk radiowy może być preferowany zamiast przycisku Wybierz. W sytuacjach, gdy użytkownik może potencjalnie wybrać wiele rekordów, takich jak w internetowej aplikacji poczty e-mail, gdzie użytkownik może chcieć wybrać wiele wiadomości do usunięcia, pole wyboru oferuje dodatkowe funkcje, które nie są dostępne w innych interfejsach użytkownika, takich jak przycisk Wybierz czy przycisk radiowy.

W tym samouczku pokazano, jak dodać kolumnę z przyciskami radiowymi do kontrolki GridView. W tym samouczku przedstawiono użycie pól wyboru.

Krok 1: Tworzenie i ulepszanie stron internetowych za pomocą GridView

Zanim zaczniemy ulepszać kontrolkę GridView, aby dodać kolumnę przycisków radiowych, najpierw poświęćmy chwilę, aby utworzyć strony ASP.NET w projekcie naszej strony internetowej, które będą potrzebne w tym samouczku i dwóch następnych. Zacznij od dodania nowego folderu o nazwie EnhancedGridView. Następnie dodaj następujące strony ASP.NET do tego folderu, aby skojarzyć każdą stronę ze stroną wzorcową Site.master :

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

Dodawanie stron ASP.NET dla samouczków związanych z usługą SqlDataSource

Rysunek 1. Dodaj strony ASP.NET dla samouczków SqlDataSource-Related

Podobnie jak w innych folderach, Default.aspx w folderze EnhancedGridView wyświetli listę samouczków w swojej sekcji. Pamiętaj, że kontrolka SectionLevelTutorialListing.ascx użytkownika udostępnia tę funkcję. W związku z tym dodaj tę kontrolkę użytkownika Default.aspx przeciągając ją z Eksploratora rozwiązań na stronę w widoku Projektu.

Dodaj kontrolkę użytkownika SectionLevelTutorialListing.ascx do Default.aspx

Rysunek 2. Dodawanie kontrolki SectionLevelTutorialListing.ascx użytkownika do Default.aspx (kliknij, aby wyświetlić obraz o pełnym rozmiarze)

Na koniec dodaj te cztery strony jako wpisy do Web.sitemap pliku. W szczególności dodaj następujący znacznik po kontrolce SqlDataSource<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>

Po zaktualizowaniu Web.sitemap programu, poświęć chwilę, aby wyświetlić witrynę internetową samouczków za pośrednictwem przeglądarki. Menu po lewej stronie zawiera teraz elementy do edycji, wstawiania i usuwania samouczków.

Mapa witryny zawiera teraz wpisy dotyczące samouczków dotyczących ulepszania GridView

Rysunek 3. Mapa witryny zawiera teraz wpisy dotyczące samouczków dotyczących ulepszania GridView

Krok 2: Wyświetlanie dostawców w widoku siatki GridView

W tym samouczku zbudujmy element GridView, który wyświetla listę dostawców z USA, a każdy wiersz GridView ma przycisk radiowy. Po wybraniu dostawcy za pośrednictwem przycisku radiowego użytkownik może wyświetlić produkty dostawcy, klikając przycisk. Chociaż to zadanie może brzmieć trywialne, istnieje wiele subtelności, które sprawiają, że szczególnie trudne. Zanim zagłębimy się w te subtelności, najpierw uzyskajmy widok siatki z listą dostawców.

Zacznij od otwarcia strony RadioButtonField.aspx w folderze EnhancedGridView, przeciągając GridView z przybornika na projektanta. Ustaw właściwość GridView ID na Suppliers i z jego inteligentnego tagu wybierz opcję utworzenia nowego źródła danych. W szczególności utwórz obiekt ObjectDataSource o nazwie SuppliersDataSource , który pobiera dane z SuppliersBLL obiektu.

Tworzenie nowego obiektuDataSource o nazwie SuppliersDataSource

Rysunek 4. Tworzenie nowego obiektuDataSource o nazwie SuppliersDataSource (kliknij, aby wyświetlić obraz o pełnym rozmiarze)

Zrzut ekranu przedstawiający okno Konfigurowanie źródła danych — SuppliersDataSource z wybranym obiektem biznesowym DostawcyBLL i wyróżnionym przyciskiem Dalej.

Rysunek 5. Konfigurowanie obiektu ObjectDataSource do używania SuppliersBLL klasy (kliknij, aby wyświetlić obraz o pełnym rozmiarze)

Ponieważ chcemy wyświetlić listę tylko tych dostawców w USA, wybierz GetSuppliersByCountry(country) metodę z listy rozwijanej na karcie SELECT.

Zrzut ekranu przedstawiający okno Konfigurowanie źródła danych — SuppliersDataSource z otwartą kartą SELECT. Opcja metody GetSupplierByCountry jest zaznaczona, a przycisk Dalej jest wyróżniony.

Rysunek 6. Konfigurowanie obiektu ObjectDataSource do używania SuppliersBLL klasy (kliknij, aby wyświetlić obraz o pełnym rozmiarze)

Na karcie AKTUALIZACJA wybierz opcję (Brak), a następnie kliknij przycisk Dalej.

Zrzut ekranu przedstawiający okno Konfigurowanie źródła danych — SuppliersDataSource z otwartą kartą UPDATE. Opcja metody (Brak) jest zaznaczona, a przycisk Dalej jest wyróżniony.

Rysunek 7. Konfigurowanie obiektu ObjectDataSource do użycia SuppliersBLL klasy (kliknij, aby wyświetlić obraz o pełnym rozmiarze)

Ponieważ metoda GetSuppliersByCountry(country) akceptuje parametr, kreator konfigurowania źródła danych pyta nas o źródło tego parametru. Aby określić ustaloną wartość (USA, w tym przykładzie), pozostaw listę rozwijaną Źródło parametrów ustawioną na Brak i wprowadź wartość domyślną w polu tekstowym. Kliknij przycisk Zakończ, aby ukończyć pracę kreatora.

Użyj usa jako wartości domyślnej dla parametru kraju

Rysunek 8. Użyj usa jako wartości domyślnej parametru country (kliknij, aby wyświetlić obraz pełnowymiarowy)

Po ukończeniu pracy kreatora kontrolka GridView będzie zawierać pole BoundField dla każdego pola danych dostawcy. Usuń wszystkie elementy CompanyName, Cityi Country BoundFields i zmień nazwę CompanyName właściwości BoundFields HeaderText na Supplier. Po wykonaniu tej czynności składni deklaratywnej GridView i ObjectDataSource powinny wyglądać podobnie do poniższej.

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

Na potrzeby tego samouczka pozwólmy użytkownikowi wyświetlić wybrane produkty dostawcy na tej samej stronie co lista dostawców lub na innej stronie. Aby to uwzględnić, dodaj do strony dwie kontrolki przycisków Web. Ustawiłem ID dla tych dwóch przycisków na ListProducts i SendToProducts, z pomysłem, że po kliknięciu na ListProducts nastąpi postback i wybrane produkty dostawcy zostaną wyświetlone na tej samej stronie, ale po kliknięciu SendToProducts, użytkownik zostanie przeniesiony na inną stronę, która wyświetla listę produktów.

Rysunek 9 przedstawia Suppliers GridView i dwa przyciski kontrolki sieci Web widoczne w przeglądarce.

Dostawcy z USA mają swoje nazwy, miasto i informacje o kraju wymienione

Rysunek 9: Dostawcy z USA mają wymienione swoje nazwy, miasto i kraj (kliknij, aby wyświetlić obraz pełnowymiarowy)

Krok 3. Dodawanie kolumny przycisków radiowych

W tym momencie Suppliers GridView ma trzy pola BoundField wyświetlające nazwę firmy, miasto i kraj każdego dostawcy w USA. Nadal brakuje jednak kolumny przycisków radiowych. Niestety, GridView nie zawiera wbudowanego pola RadioButtonField, inaczej moglibyśmy po prostu dodać je do siatki i gotowe. Zamiast tego możemy dodać pole szablonu TemplateField i skonfigurować jego ItemTemplate, aby renderować przycisk radiowy, co spowoduje, że w każdym wierszu kontrolki GridView zostanie wyświetlony przycisk radiowy.

Początkowo można założyć, że żądany interfejs użytkownika można zaimplementować przez dodanie kontrolki Sieci Web RadioButton do ItemTemplate pola szablonu. Chociaż spowoduje to rzeczywiście dodanie jednego przycisku radiowego do każdego wiersza kontrolki GridView, przyciski radiowe nie mogą być grupowane i dlatego nie wykluczają się wzajemnie. Oznacza to, że użytkownik końcowy może jednocześnie wybrać wiele przycisków radiowych z kontrolki GridView.

Mimo że użycie kontrolki TemplateField of RadioButton Web nie oferuje potrzebnych funkcji, zaimplementujmy to podejście, ponieważ warto sprawdzić, dlaczego wynikowe przyciski radiowe nie są grupowane. Zacznij od dodania pola TemplateField do kontrolki GridView dostawców, dzięki czemu jest to najbardziej lewe pole. Następnie z tagu inteligentnego GridView kliknij link Edytuj szablony i przeciągnij kontrolkę Sieci Web RadioButton z przybornika do pola szablonu ItemTemplate (zobacz Rysunek 10). Ustaw właściwość ID RadioButton na RowSelector oraz właściwość GroupName na SuppliersGroup.

Dodaj kontrolkę sieciową RadioButton do ItemTemplate

Rysunek 10: Dodaj kontrolkę internetową RadioButton do ItemTemplate (Kliknij, aby wyświetlić obraz o pełnym rozmiarze)

Po dokonaniu tych uaktualnień za pomocą Projektanta, znaczniki GridView powinny wyglądać podobnie do poniższych:

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

Właściwość RadioButton GroupName jest używana do grupowania serii przycisków radiowych. Wszystkie kontrolki RadioButton o tej samej GroupName wartości są traktowane jako zgrupowane; jednocześnie można wybrać tylko jeden przycisk radiowy z grupy. Właściwość GroupName określa wartość atrybutu name renderowanego przycisku radiowego. Przeglądarka sprawdza atrybuty przycisków radiowych name w celu określenia grup przycisków radiowych.

Po dodaniu kontrolki RadioButton Web do ItemTemplateelementu przejdź do tej strony za pośrednictwem przeglądarki i kliknij przyciski radiowe w wierszach siatki. Zwróć uwagę, że przyciski radiowe nie są grupowane, dzięki czemu można wybrać wszystkie rzędy, jak pokazano na rysunku 11.

Przyciski radiowe GridView nie są grupowane

Rysunek 11. Przyciski radiowe kontrolki GridView nie są grupowane (kliknij, aby wyświetlić obraz pełnowymiarowy)

Powodem, dla którego przyciski radiowe nie są grupowane, jest to, że ich renderowane name atrybuty są różne, mimo że mają to samo GroupName ustawienie właściwości. Aby zobaczyć te różnice, wykonaj widok/źródło w przeglądarce i sprawdź znacznik przycisku radiowego:

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

Zwróć uwagę, że zarówno name atrybuty, jak i id nie są dokładnymi wartościami określonymi w oknie Właściwości, ale są poprzedzane wieloma innymi ID wartościami. Dodatkowe ID wartości dodane do przodu renderowanych atrybutów id i name to ID elementów nadrzędnych przycisków radiowych, kontrolki GridViewRow, siatki GridViewID, kontrolki zawartości ID oraz formularza sieci WebID. Są one ID dodawane tak, aby każda renderowana kontrolka sieci Web w GridView miała unikatowe wartości id i name.

Każda renderowana kontrolka wymaga innego name i id, ponieważ przeglądarka jednoznacznie identyfikuje każdą kontrolkę po stronie klienta i informuje serwer internetowy, jaka akcja lub zmiana wystąpiła po przesłaniu zwrotnym. Załóżmy na przykład, że chcemy uruchomić kod po stronie serwera za każdym razem, gdy zmieni się stan zaznaczenia RadioButton. Możemy to osiągnąć, ustawiając właściwość RadioButton AutoPostBack na true i tworząc program obsługi dla zdarzenia CheckChanged. Jeśli jednak renderowane wartości dla name i id we wszystkich przyciskach radiowych były takie same, to w momencie ogłaszania zwrotnego nie można było określić, który konkretny przycisk radiowy został kliknięty.

Krótko mówiąc, nie możemy utworzyć kolumny przycisków radiowych w kontrolce GridView przy użyciu kontrolki RadioButton Web. Zamiast tego musimy użyć raczej archaicznych technik, aby upewnić się, że odpowiedni znacznik jest wstrzykiwany do każdego wiersza GridView.

Uwaga / Notatka

Podobnie jak kontrolka RadioButton Web, kontrolka HTML przycisku opcji, po dodaniu do szablonu, będzie zawierać unikatowy name atrybut, co powoduje, że przyciski opcji w siatce są niezgrupowane. Jeśli nie znasz kontrolek HTML, możesz zignorować tę notatkę, ponieważ kontrolki HTML są rzadko używane, zwłaszcza w ASP.NET 2.0. Jeśli jednak chcesz dowiedzieć się więcej, zobacz wpis w blogu K. Scott AllenWeb Controls i kontrolki HTML.

Używanie kontroli Literal do wstrzykiwania znaczników przycisku radiowego

Aby poprawnie zgrupować wszystkie przyciski radiowe w GridView, musimy ręcznie wstrzyknąć znaczniki przycisków radiowych do ItemTemplate. Każdy przycisk radiowy wymaga tego samego name atrybutu, ale powinien mieć unikatowy id atrybut (w przypadku, gdy chcemy uzyskać dostęp do przycisku radiowego za pośrednictwem skryptu po stronie klienta). Gdy użytkownik wybierze przycisk radiowy i opublikuje stronę z powrotem, przeglądarka wyśle z powrotem wartość wybranego atrybutu value przycisku radiowego. W związku z tym każdy przycisk radiowy będzie potrzebować unikatowego value atrybutu. Na koniec w przypadku przesyłania zwrotnego musimy pamiętać o dodaniu atrybutu checked do wybranego przycisku radiowego, w przeciwnym razie po wybraniu przez użytkownika i przesłaniu zwrotnym ich stan powróci do domyślnego (wszystkie niezaznaczone).

Istnieją dwa podejścia, które można zastosować w celu wprowadzenia znaczników niskiego poziomu do szablonu. Jedną z metod jest zastosowanie kombinacji znaczników i wywołań metod formatowania zdefiniowanych w klasie kodu w tle. Ta technika została po raz pierwszy omówiona w samouczku Using TemplateFields (Używanie pól szablonu w kontrolce GridView ). W naszym przypadku może to wyglądać mniej więcej tak:

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

W tym miejscu GetUniqueRadioButton i GetRadioButtonValue będą metodami zdefiniowanymi w klasie code-behind, które zwracają odpowiednie wartości atrybutów id i value dla każdego przycisku radiowego. Podejście to dobrze sprawdza się w przypisywaniu atrybutów id i value, ale okazuje się niewystarczające, gdy trzeba określić wartość atrybutu checked, ponieważ składnia powiązania danych wykonywana jest dopiero wtedy, gdy dane są po raz pierwszy powiązane z kontrolką GridView. W związku z tym, jeśli kontrolka GridView ma włączony stan widoku, metody formatowania będą uruchamiane tylko wtedy, gdy strona zostanie załadowana po raz pierwszy (lub gdy element GridView jest jawnie związany ze źródłem danych), a zatem funkcja, która ustawia atrybut checked, nie zostanie wywołana przy odświeżeniu strony. Jest to dość subtelny problem i nieco poza zakresem tego artykułu, więc zostawię go w tym miejscu. Zachęcam jednak do wypróbowania tego podejścia i pracy z nim do momentu, w którym utkniesz. Chociaż takie ćwiczenie nie przybliży Cię do wersji roboczej, pomoże to lepiej zrozumieć element GridView i cykl życia powiązania danych.

Inne podejście do wstrzykiwania niestandardowych, niskiego poziomu znaczników w szablonie i podejście, którego użyjemy na potrzeby tego samouczka, polega na dodaniu kontrolki Literał do szablonu. Następnie w procedurze obsługi zdarzeń RowCreated lub RowDataBound dla GridView można programowo uzyskać dostęp do kontrolki Literał i ustawić jej właściwość Text na znaczniki do emisji.

Zacznij od usunięcia przycisku RadioButton z TemplateField ItemTemplate, zastępując go kontrolką Literal. Ustaw kontrolkę Literał ID na wartość RadioButtonMarkup.

Dodaj kontrolkę literału do ItemTemplate

Rysunek 12: Dodaj kontrolkę literału do ItemTemplate (Kliknij, aby wyświetlić pełnowymiarowy obraz)

Następnie utwórz procedurę obsługi zdarzeń dla zdarzenia GridView.RowCreated Zdarzenie RowCreated jest uruchamiane raz dla każdego dodanego wiersza, niezależnie od tego, czy dane są przywracane do widoku GridView. Oznacza to, że nawet w przypadku powrotu, gdy dane są ponownie ładowane ze stanu widoku, zdarzenie RowCreated nadal jest uruchamiane i dlatego używamy go zamiast RowDataBound (które jest uruchamiane tylko wtedy, gdy dane są jawnie powiązane z kontrolką sieci Web danych).

W tym programie obsługi zdarzeń chcemy kontynuować tylko wtedy, gdy mamy do czynienia z wierszem danych. Dla każdego wiersza danych chcemy programowo odwołać się do kontrolki RadioButtonMarkup Literał i ustawić jej właściwość Text tak, aby mógł emitować znacznik. Jak pokazano w poniższym kodzie, znacznik emitowany tworzy przycisk radiowy, którego name atrybut jest ustawiony na SuppliersGroup, którego id atrybut jest ustawiony na RowSelectorX, gdzie X jest indeksem wiersza GridView i którego value atrybut jest ustawiony na indeks wiersza 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);
    }
}

Po wybraniu wiersza GridView i wystąpieniu odświeżenia strony, jesteśmy zainteresowani SupplierID wybranego dostawcy. Dlatego można pomyśleć, że wartość każdego przycisku radiowego powinna być rzeczywista SupplierID (a nie indeks wiersza GridView). Chociaż może to działać w pewnych okolicznościach, stanowiłoby zagrożenie dla bezpieczeństwa, gdyby ślepo zaakceptować i przetworzyć element SupplierID. Nasz element GridView, na przykład, zawiera listę tylko tych dostawców w USA. Jednak jeśli SupplierID jest przekazywany bezpośrednio z przycisku radiowego, co powstrzyma złośliwego użytkownika przed manipulowaniem wartością SupplierID wysłaną z powrotem po zakończeniu przesyłania? Korzystając z indeksu wiersza jako value, a następnie pobierając SupplierID w zwrocie z kolekcji DataKeys, możemy upewnić się, że użytkownik korzysta tylko z jednej wartości SupplierID skojarzonej z jednym z wierszy GridView.

Po dodaniu tego kodu procedury obsługi zdarzeń poświęć chwilę, aby przetestować stronę w przeglądarce. Najpierw należy pamiętać, że jednocześnie można wybrać tylko jeden przycisk radiowy w tabeli. Jednak po wybraniu przycisku radiowego i kliknięciu jednego z przycisków następuje ponowne wysłanie danych, a przyciski radiowe zostają przywrócone do początkowego stanu. Oznacza to, że po ponownym wysłaniu danych wybrany przycisk radiowy nie jest już zaznaczony. Aby rozwiązać ten problem, musimy rozszerzyć RowCreated program obsługi zdarzeń, tak aby sprawdzał wybrany indeks przycisku radiowego wysłany z ogłaszania zwrotnego i dodaje checked="checked" atrybut do emitowanego znacznika dopasowania indeksu wierszy.

W przypadku wystąpienia postbacku przeglądarka wysyła z powrotem name i value wybranego przycisku radiowego. Wartość można pobrać programowo przy użyciu polecenia Request.Form["name"]. WłaściwośćRequest.Form udostępnia reprezentację NameValueCollection zmiennych formularza. Zmienne formularza to nazwy i wartości pól formularza na stronie internetowej, które są przesyłane z powrotem przez przeglądarkę internetową za każdym razem, gdy następuje ponowne przesłanie danych (postback). Ponieważ renderowany atrybut name przycisków radiowych w GridView to SuppliersGroup, gdy strona internetowa zostanie wysłana z powrotem, przeglądarka odeśle SuppliersGroup=valueOfSelectedRadioButton do serwera internetowego (wraz z innymi polami formularza). Dostęp do tych informacji zostanie uzyskany z właściwości Request.Form przy użyciu: Request.Form["SuppliersGroup"].

Ponieważ musimy określić wybrany indeks przycisku radiowego nie tylko w RowCreated procedurze obsługi zdarzenia, ale także w Click procedurach obsługi zdarzeń dla kontrolek przycisku sieci Web, dodajmy SuppliersSelectedIndex właściwość do klasy zaplecza kodu, która zwraca -1, jeśli nie wybrano przycisku radiowego, i wybrany indeks, jeśli wybrano jeden z przycisków radiowych.

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

Po dodaniu tej właściwości wiemy, aby dodać znacznik checked="checked" w programie obsługi zdarzenia RowCreated, gdy SuppliersSelectedIndex równa się e.Row.RowIndex. Zaktualizuj program obsługi zdarzeń, aby uwzględnić tę logikę:

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 += " />";
    }
}

Dzięki tej zmianie wybrany przycisk radiowy pozostaje wybrany po przeładowaniu strony. Teraz, mając możliwość określenia, który przycisk radiowy jest zaznaczony, możemy zmienić zachowanie strony tak, aby przy pierwszym jej odwiedzeniu był zaznaczony przycisk radiowy w pierwszym wierszu GridView (zamiast tego, co jest obecnym zachowaniem, że żaden przycisk radiowy nie jest wybrany domyślnie). Aby domyślnie wybrać pierwszy przycisk radiowy, po prostu zmień instrukcję if (SuppliersSelectedIndex == e.Row.RowIndex) na następującą: if (SuppliersSelectedIndex == e.Row.RowIndex || (!Page.IsPostBack && e.Row.RowIndex == 0)).

W tym momencie dodaliśmy do kontrolki GridView kolumnę pogrupowanych przycisków radiowych, która umożliwia wybranie pojedynczego wiersza i jego zapamiętanie między postbackami. Następne kroki to wyświetlenie produktów dostarczonych przez wybranego dostawcę. W kroku 4 zobaczymy, jak przekierować użytkownika do innej strony, wysyłając wybranySupplierID. W kroku 5 zobaczymy, jak wyświetlić produkty wybranego dostawcy w GridView na tej samej stronie.

Uwaga / Notatka

Zamiast używać pola TemplateField (fokus tego długiego kroku 3), możemy utworzyć klasę niestandardową DataControlField , która renderuje odpowiedni interfejs użytkownika i funkcjonalność. KlasaDataControlField jest klasą bazową, z której pochodzą pola BoundField, CheckBoxField, TemplateField i inne wbudowane pola GridView i DetailsView. Utworzenie klasy niestandardowej DataControlField oznaczałoby, że kolumna przycisków radiowych mogłaby być dodana jedynie przy użyciu składni deklaratywnej i znacznie ułatwiłoby to replikowanie funkcjonalności na innych stronach internetowych oraz w innych aplikacjach internetowych.

Jeśli kiedykolwiek utworzyłeś niestandardowe, skompilowane elementy sterujące w ASP.NET, wiesz, że wymaga to sporo pracy i wiąże się z wieloma subtelnościami oraz przypadkami brzegowymi, które muszą być starannie obsługiwane. W związku z tym na razie zrezygnujemy z wdrażania kolumny przycisków radiowych jako klasy niestandardowej DataControlField i będziemy trzymać się opcji TemplateField. Być może będziemy mieli okazję zapoznać się z tworzeniem, używaniem i wdrażaniem klas niestandardowych DataControlField w przyszłym samouczku.

Krok 4. Wyświetlanie wybranych produktów dostawcy na oddzielnej stronie

Gdy użytkownik wybrał wiersz GridView, musimy wyświetlić wybrane produkty dostawcy. W niektórych okolicznościach możemy chcieć wyświetlić te produkty na osobnej stronie, w innych możemy preferować zrobienie tego na tej samej stronie. Zacznijmy od zbadania, jak wyświetlać produkty na osobnej stronie; w kroku 5 przyjrzymy się dodaniu kontrolki GridView do RadioButtonField.aspx, aby wyświetlić produkty wybranego dostawcy.

Obecnie na stronie znajdują się dwie kontrolki przycisków sieci Web ListProducts i SendToProducts. Po kliknięciu SendToProducts przycisku chcemy wysłać użytkownika do ~/Filtering/ProductsForSupplierDetails.aspx. Ta strona została utworzona w tutorialu Filtrowanie wzorca/szczegółów na dwóch stronach i wyświetla produkty dostawcy, którego SupplierID są przekazywane przez pole ciągu zapytania o nazwie SupplierID.

Aby zapewnić tę funkcję, utwórz procedurę obsługi zdarzeń dla zdarzenia SendToProducts przycisku Click. W kroku 3 dodaliśmy właściwość SuppliersSelectedIndex, która zwraca indeks wiersza, dla którego zaznaczono przycisk radiowy. Odpowiednie SupplierID można pobrać z kolekcji GridView DataKeys, a użytkownik może następnie zostać przekierowany do ~/Filtering/ProductsForSupplierDetails.aspx?SupplierID=SupplierID przy użyciu 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);
    }
}

Ten kod działa cudownie, o ile jeden z przycisków radiowych jest wybierany z kontrolki GridView. Jeśli początkowo w kontrolce GridView nie jest wybrany żaden przycisk radiowy i użytkownik kliknie przycisk SendToProducts, SuppliersSelectedIndex będzie -1, co spowoduje zgłoszenie wyjątku, ponieważ -1 znajduje się poza zakresem indeksu kolekcji DataKeys. Nie jest to jednak problem, jeśli zdecydujesz się zaktualizować RowCreated procedurę obsługi zdarzeń zgodnie z opisem w kroku 3, aby pierwszy przycisk radiowy w GridView był początkowo wybrany.

Aby uwzględnić SuppliersSelectedIndex wartość -1, dodaj kontrolkę Etykieta sieci Web do strony powyżej kontrolki GridView. Ustaw jej ID właściwość na ChooseSupplierMsg, jej CssClass właściwość na Warning, jej właściwości EnableViewState i Visible na false, i jej Text właściwość na Proszę wybrać dostawcę z tabeli. Klasa CSS Warning wyświetla tekst dużą czerwoną pogrubioną kursywą czcionką i jest zdefiniowana w Styles.css. Ustawiając właściwości EnableViewState i Visible na false, etykieta nie jest renderowana, z wyjątkiem tych postbacków, w których właściwość kontrolki Visible jest programowo ustawiona na true.

Dodaj kontrolkę webową etykiety nad kontrolką GridView

Rysunek 13. Dodaj kontrolkę etykiety web nad kontrolką GridView (kliknij, aby wyświetlić obraz w pełnym rozmiarze)

Następnie rozszerz Click procedurę obsługi zdarzeń, aby wyświetlić etykietę ChooseSupplierMsg, jeśli SuppliersSelectedIndex jest mniejsza niż zero, i przekieruj użytkownika do ~/Filtering/ProductsForSupplierDetails.aspx?SupplierID=SupplierID w przeciwnym razie.

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);
    }
}

Odwiedź stronę w przeglądarce i kliknij przycisk SendToProducts zanim wybierzesz dostawcę z widżetu GridView. Jak pokazano na rysunku 14, zostanie wyświetlona etykieta ChooseSupplierMsg . Następnie wybierz dostawcę i kliknij SendToProducts przycisk . To przeniesie Cię na stronę zawierającą listę produktów dostarczonych przez wybranego dostawcę. Rysunek 15 przedstawia ProductsForSupplierDetails.aspx stronę, na której został wybrany dostawca Bigfoot Breweries.

Etykieta ChooseSupplierMsg jest wyświetlana, jeśli nie wybrano dostawcy

Rysunek 14. Etykieta ChooseSupplierMsg jest wyświetlana, jeśli nie wybrano dostawcy (kliknij, aby wyświetlić obraz o pełnym rozmiarze)

Wybrane produkty dostawcy są wyświetlane w ProductsForSupplierDetails.aspx

Rysunek 15. Wyświetlane ProductsForSupplierDetails.aspx są wybrane produkty dostawcy (kliknij, aby wyświetlić obraz pełnowymiarowy)

Krok 5. Wyświetlanie wybranych produktów dostawcy na tej samej stronie

W kroku 4 pokazano, jak wysłać użytkownika do innej strony internetowej, aby wyświetlić wybrane produkty dostawcy. Alternatywnie wybrane produkty dostawcy mogą być wyświetlane na tej samej stronie. Aby to zilustrować, dodamy kolejny element GridView do RadioButtonField.aspx, aby wyświetlić produkty wybranego dostawcy.

Ponieważ chcemy, aby ta kontrolka GridView produktów była wyświetlana tylko po wybraniu dostawcy, dodaj kontrolkę Panel sieci Web pod Suppliers kontrolką GridView, ustawiając jej ID właściwość na ProductsBySupplierPanel i jej Visible właściwość na false. W panelu dodaj tekst "Produkty dla wybranego dostawcy", a następnie GridView o nazwie ProductsBySupplier. W tagu inteligentnym GridView wybierz powiązanie go z nowym obiektem ObjectDataSource o nazwie ProductsBySupplierDataSource.

Wiązanie elementu ProductsBySupplier GridView z nowym obiektem ObjectDataSource

Rysunek 16. Powiązanie kontrolki ProductsBySupplier GridView z nowym obiektem ObjectDataSource (kliknij, aby wyświetlić obraz o pełnym rozmiarze)

Następnie skonfiguruj obiekt ObjectDataSource do używania ProductsBLL klasy . Ponieważ chcemy pobrać tylko te produkty dostarczone przez wybranego dostawcę, określ, że obiekt ObjectDataSource powinien wywołać metodę GetProductsBySupplierID(supplierID) w celu pobrania danych. Wybierz pozycję (Brak) z list rozwijanych na kartach UPDATE, INSERT i DELETE.

Konfigurowanie obiektu ObjectDataSource do używania metody GetProductsBySupplierID(supplierID)

Rysunek 17. Konfigurowanie obiektu ObjectDataSource do użycia GetProductsBySupplierID(supplierID) metody (kliknij, aby wyświetlić obraz o pełnym rozmiarze)

Ustaw listy Drop-Down na (Brak) w kartach UPDATE, INSERT i DELETE

Rysunek 18. Ustawianie listy Drop-Down na wartość (Brak) na kartach UPDATE, INSERT i DELETE (Kliknij, aby wyświetlić obraz o pełnym rozmiarze)

Po skonfigurowaniu kart SELECT, UPDATE, INSERT i DELETE kliknij przycisk Dalej. GetProductsBySupplierID(supplierID) Ponieważ metoda oczekuje parametru wejściowego, kreator tworzenia źródła danych monituje nas o określenie źródła dla wartości parametru.

W tym miejscu mamy kilka opcji określania źródła wartości parametru. Możemy użyć domyślnego obiektu Parametr i programowo przypisać wartość SuppliersSelectedIndex właściwości do właściwości Parameter w DefaultValue programie obsługi zdarzeń ObjectDataSource Selecting . Zapoznaj się z samouczkiem Programmatically Setting the ObjectDataSource's Parameter Values, aby odświeżyć wiedzę na temat programowego przypisywania wartości do parametrów ObjectDataSource.

Alternatywnie możemy użyć kontrolki ControlParameter i odwołać się do Suppliers właściwości GridView SelectedValue (zobacz Rysunek 19). Właściwość SelectedValue GridView zwraca wartość DataKey odpowiadającą właściwości SelectedIndex. Aby ta opcja działała, musimy programowo ustawić właściwość SelectedIndex kontrolki GridView na wybrany wiersz po kliknięciu przycisku ListProducts. Dodatkową korzyścią jest to, że po ustawieniu SelectedIndex, wybrany rekord przejmie SelectedRowStyle zdefiniowane w motywie DataWebControls (żółte tło).

Użyj parametru ControlParameter, aby określić element GridView s SelectedValue jako źródło parametru

Rysunek 19: Użyj ParametrKontroli, aby określić WybranąWartość kontroli GridView jako źródło parametru (kliknij, aby zobaczyć obraz w pełnym rozmiarze)

Po ukończeniu pracy kreatora program Visual Studio automatycznie doda pola dla pól danych produktu. Usuń wszystkie elementy poza polami ProductName, CategoryName i UnitPrice BoundFields, i zmień właściwości HeaderText na "Product", "Category" i "Price". Skonfiguruj pole UnitPrice BoundField tak, aby jego wartość została sformatowana jako waluta. Po wprowadzeniu tych zmian znaczniki deklaratywne Panel, GridView i ObjectDataSource powinny wyglądać następująco:

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

Aby ukończyć to ćwiczenie, musimy ustawić właściwość dla GridView SelectedIndex na SelectedSuppliersIndex oraz właściwość dla Panelu ProductsBySupplierPanel na Visible po kliknięciu przycisku true. W tym celu utwórz procedurę obsługi zdarzeń dla kontrolki sieci Web przycisk ListProducts w zdarzeniu Click i dodaj następujący kod:

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

Jeśli dostawca nie został wybrany z kontrolki GridView, etykieta ChooseSupplierMsg jest wyświetlana, a panel ProductsBySupplierPanel jest ukryty. W przeciwnym razie, jeśli dostawca został wybrany, ProductsBySupplierPanel jest wyświetlany i właściwość SelectedIndex GridView jest aktualizowana.

Rysunek 20 przedstawia wyniki po wybraniu dostawcy Bigfoot Breweries i kliknięciu przycisku Pokaż produkty na stronie.

Produkty dostarczone przez Bigfoot Breweries są wymienione na tej samej stronie

Rysunek 20. Produkty dostarczone przez Bigfoot Breweries są wyświetlane na tej samej stronie (kliknij, aby wyświetlić obraz pełnowymiarowy)

Podsumowanie

Zgodnie z opisem w samouczku Master/Detail Using a Selectable Master GridView with a Details DetailView, rekordy można wybrać z kontrolki GridView, używając pola CommandField, którego właściwość ShowSelectButton jest ustawiona na true. Jednak pole CommandField wyświetla przyciski albo jako standardowe przyciski, albo jako linki lub obrazy. Alternatywny interfejs użytkownika wyboru wiersza polega na podaniu przycisku radiowego lub pola wyboru w każdym wierszu GridView. W tym samouczku przeanalizowaliśmy, jak dodać kolumnę przycisków radiowych.

Niestety dodanie kolumny przycisków radiowych nie jest tak proste, jak można się spodziewać. Nie ma wbudowanego pola RadioButtonField, który można dodać po kliknięciu przycisku, a użycie kontrolki RadioButton w sieci Web w polu TemplateField powoduje własny zestaw problemów. W końcu, aby zapewnić taki interfejs, musimy utworzyć klasę niestandardową DataControlField lub uciekać się do wstrzykiwania odpowiedniego kodu HTML do pola TemplateField podczas RowCreated zdarzenia.

Po zapoznaniu się z dodawaniem kolumny przycisków radiowych zwróćmy uwagę na dodanie kolumny pól wyboru. Przy użyciu kolumny pól wyboru użytkownik może wybrać co najmniej jeden wiersz GridView, a następnie wykonać operację na wszystkich wybranych wierszach (takich jak wybranie zestawu wiadomości e-mail z internetowego klienta poczty e-mail, a następnie wybranie usunięcia wszystkich wybranych wiadomości e-mail). W następnym poradniku pokażemy, jak dodać taką kolumnę.

Szczęśliwe programowanie!

Informacje o autorze

Scott Mitchell, autor siedmiu książek ASP/ASP.NET i założyciel 4GuysFromRolla.com, współpracuje z technologiami internetowymi firmy Microsoft od 1998 roku. Scott pracuje jako niezależny konsultant, trener i pisarz. Jego najnowsza książka to Sams Teach Yourself ASP.NET 2.0 w ciągu 24 godzin. Można go uzyskać pod adresem mitchell@4GuysFromRolla.com.

Specjalne podziękowania

Ta seria samouczków została omówiona przez wielu przydatnych recenzentów. Głównym recenzentem tego samouczka był David Suru. Chcesz przejrzeć nadchodzące artykuły MSDN? Jeśli tak, napisz do mnie na adres mitchell@4GuysFromRolla.com.