Filtrowanie wzorca/szczegółów na dwóch stronach przy użyciu kontrolki repeatera i listy danych (C#)

Autor: Scott Mitchell

Pobierz plik PDF

W tym samouczku przyjrzymy się, jak oddzielić raport główny/szczegółowy na dwóch stronach. Na stronie "master" używamy kontrolki Repeater do renderowania listy kategorii, które po kliknięciu spowoduje przejście użytkownika do strony "szczegóły", na której dwukolumna lista danych zawiera te produkty należące do wybranej kategorii.

Wprowadzenie

W poprzednim samouczku pokazano, jak wyświetlać raporty wzorca/szczegółów na jednej stronie internetowej przy użyciu list Rozwijanych w celu wyświetlenia rekordów "master" i listy DataList w celu wyświetlenia "szczegółów". Innym typowym wzorcem używanym do raportów wzorca/szczegółów jest posiadanie rekordów wzorcowych na jednej stronie internetowej i szczegółów na innej. We wcześniejszym samouczku Filtrowanie wzorca/szczegółów na dwóch stronach przeanalizowaliśmy ten wzorzec przy użyciu kontrolki GridView, aby wyświetlić wszystkich dostawców w systemie. Ten element GridView zawierał funkcję HyperLinkField, która została renderowana jako link do drugiej strony, przekazując element SupplierID w ciągu zapytania. Druga strona użyła elementu GridView do wyświetlenia listy tych produktów dostarczonych przez wybranego dostawcę.

Takie dwustronicowe raporty wzorcowe/szczegółowe można również wykonać przy użyciu kontrolek DataList i Repeater. Jedyną różnicą jest to, że ani element DataList, ani Repeater nie zapewnia obsługi kontrolki HyperLinkField. Zamiast tego musimy dodać kontrolkę sieci Web funkcji HyperLink lub zakotwiczyć element HTML (<a>) w kontrolce ItemTemplate. Właściwość funkcji HyperLink NavigateUrl lub atrybut kotwicy href można następnie dostosować przy użyciu metod deklaratywnych lub programowych.

W tym samouczku zapoznamy się z przykładem, który zawiera listę kategorii na liście punktowanej na jednej stronie przy użyciu kontrolki Repeater. Każdy element listy będzie zawierać nazwę i opis kategorii z nazwą kategorii wyświetlaną jako link do drugiej strony. Kliknięcie tego linku spowoduje wąsanie użytkownika na drugą stronę, gdzie lista Danych wyświetli te produkty należące do wybranej kategorii.

Krok 1. Wyświetlanie kategorii na liście punktowanej

Pierwszym krokiem tworzenia dowolnego raportu głównego/szczegółowego jest rozpoczęcie od wyświetlenia rekordów "master". Dlatego naszym pierwszym zadaniem jest wyświetlenie kategorii na stronie "wzorcowej". CategoryListMaster.aspx Otwórz stronę w folderzeDataListRepeaterFiltering, dodaj kontrolkę Repeater, a następnie z tagu inteligentnego wybierz opcję dodania nowego obiektu ObjectDataSource. Skonfiguruj nowy obiekt ObjectDataSource, aby uzyskiwał dostęp do danych z CategoriesBLL metody klasy GetCategories (zobacz Rysunek 1).

Konfigurowanie obiektu ObjectDataSource do używania metody GetCategories klasy KategoriiBLL

Rysunek 1. Konfigurowanie obiektu ObjectDataSource do używania CategoriesBLLGetCategories metody klasy (kliknij, aby wyświetlić obraz pełnowymiarowy)

Następnie zdefiniuj szablony repeatera, tak aby wyświetlały każdą nazwę i opis kategorii jako element na liście punktowanej. Nie martwmy się jeszcze o to, aby każda kategoria łączyła się ze stroną szczegółów. Poniżej przedstawiono deklaratywne znaczniki dla elementu Repeater i ObjectDataSource:

<asp:Repeater ID="Repeater1" runat="server" DataSourceID="ObjectDataSource1"
    EnableViewState="False">
    <HeaderTemplate>
        <ul>
    </HeaderTemplate>
 
    <ItemTemplate>
        <li><%# Eval("CategoryName") %> - <%# Eval("Description") %></li>
    </ItemTemplate>
 
    <FooterTemplate>
        </ul>
    </FooterTemplate>
</asp:Repeater>
 
<asp:ObjectDataSource ID="ObjectDataSource1" runat="server"
    OldValuesParameterFormatString="original_{0}"
    SelectMethod="GetCategories" TypeName="CategoriesBLL">
</asp:ObjectDataSource>

Po zakończeniu znaczników poświęć chwilę, aby wyświetlić postęp w przeglądarce. Jak pokazano na rysunku 2, repeater jest renderowany jako lista punktowana przedstawiająca nazwę i opis każdej kategorii.

Każda kategoria jest wyświetlana jako element listy punktowanej

Rysunek 2. Każda kategoria jest wyświetlana jako element listy punktowanej (kliknij, aby wyświetlić obraz pełnowymiarowy)

Aby umożliwić użytkownikowi wyświetlanie informacji o "szczegółach" dla danej kategorii, musimy dodać link do każdego elementu listy punktowanej, który po kliknięciu spowoduje przejście użytkownika na drugą stronę (ProductsForCategoryDetails.aspx). Druga strona spowoduje wyświetlenie produktów dla wybranej kategorii przy użyciu listy danych. Aby określić kategorię, której link został kliknięt, musimy przekazać klikniętą kategorię CategoryID do drugiej strony za pośrednictwem pewnego mechanizmu. Najprostszym, najprostszym sposobem transferu danych skalarnych z jednej strony do innej jest użycie ciągu zapytania, czyli opcji, której użyjemy w tym samouczku. W szczególności strona będzie oczekiwać przekazania ProductsForCategoryDetails.aspx wybranej categoryID wartości za pośrednictwem pola ciągu zapytania o nazwie CategoryID. Aby na przykład wyświetlić produkty kategorii Napoje, które mają CategoryID wartość 1, użytkownik odwiedzi stronę ProductsForCategoryDetails.aspx?CategoryID=1.

Aby utworzyć hiperlink dla każdego elementu listy punktowanej w repeaterze, musimy dodać kontrolkę sieci Web funkcji HyperLink lub element kotwicy HTML (<a>) do ItemTemplateelementu . W scenariuszach, w których hiperlink jest wyświetlany tak samo dla każdego wiersza, wystarczy każde podejście. W przypadku repeaters preferuję używanie elementu kotwicy. Aby użyć elementu kotwicy, zaktualizuj element ItemTemplate repeatera do:

<li>
    <a href='ProductsForCategoryDetails.aspx?CategoryID=<%# Eval("CategoryID") %>'>
        <%# Eval("CategoryName") %>
    </a> - <%# Eval("Description") %>
</li>

Należy pamiętać, że CategoryID element można wstrzyknąć bezpośrednio w atrybucie elementu href kotwicy, jednak w tym celu należy pamiętać, aby rozdzielić href wartość atrybutu apostrofami (i znaki cudzysłowu), ponieważ Eval metoda w obrębie atrybutu href rozdziela jego ciąg ("CategoryID") znakiem cudzysłowu. Zamiast tego można użyć kontrolki sieci Web funkcji HyperLink:

<li>
    <asp:HyperLink runat="server" Text='<%# Eval("CategoryName") %>'
        NavigateUrl='<%# "ProductsForCategoryDetails.aspx?CategoryID=" &
            Eval("CategoryID") %>'>
    </asp:HyperLink>
    - <%# Eval("Description") %>
</li>

Zwróć uwagę, jak statyczna część adresu URL — ProductsForCategoryDetails.aspx?CategoryID jest dołączana do wyniku Eval("CategoryID") bezpośrednio w składni powiązania danych przy użyciu łączenia ciągów.

Jedną z zalet korzystania z kontrolki HyperLink jest możliwość programowego uzyskiwania dostępu z programu obsługi zdarzeń repeatera ItemDataBound , jeśli jest to konieczne. Na przykład możesz wyświetlić nazwę kategorii jako tekst, a nie jako link dla kategorii bez skojarzonych produktów. Takie sprawdzenie może być wykonywane programowo w ItemDataBound procedurze obsługi zdarzeń. W przypadku kategorii bez skojarzonych produktów właściwość HyperLink NavigateUrl może zostać ustawiona na pusty ciąg, co spowoduje renderowanie tej konkretnej nazwy kategorii jako zwykłego tekstu (a nie jako linku). Aby uzyskać więcej informacji na temat formatowania zawartości Elementu DataList i Repeatera na podstawie danych , zapoznaj się z samouczkiem Dotyczącym formatowania zawartości elementu DataList i Repeater w oparciu o logikę programową za pośrednictwem programu obsługi zdarzeń ItemDataBound .

Jeśli wykonasz poniższe czynności, możesz użyć metody kontroli funkcji HyperLink lub elementu kotwicy na stronie. Niezależnie od podejścia podczas przeglądania strony za pośrednictwem przeglądarki każda nazwa kategorii powinna być renderowana jako link do ProductsForCategoryDetails.aspxmetody , przekazując odpowiednią CategoryID wartość (patrz Rysunek 3).

Nazwy kategorii teraz łączą się z ProductsForCategoryDetails.aspx

Rysunek 3. Łącze nazw kategorii do ProductsForCategoryDetails.aspx (kliknij, aby wyświetlić obraz pełnowymiarowy)

Krok 3. Wyświetlanie listy produktów należących do wybranej kategorii

Po zakończeniu CategoryListMaster.aspx strony możemy zwrócić uwagę na implementację strony ProductsForCategoryDetails.aspx"szczegóły" . Otwórz tę stronę, przeciągnij listę DataList z przybornika na Projektant i ustaw jej ID właściwość na ProductsInCategory. Następnie z tagu inteligentnego DataList wybierz opcję dodania nowego obiektu ObjectDataSource do strony, nazewnictwa go ProductsInCategoryDataSource. Skonfiguruj ją tak, aby wywołuje ProductsBLL metodę klasy GetProductsByCategoryID(categoryID) ; ustaw listę rozwijaną na kartach INSERT, UPDATE i DELETE na wartość (Brak).

Konfigurowanie obiektu ObjectDataSource do użycia metody GetProductsByCategoryID(categoryID) klasy ProductsBLL

Rysunek 4. Konfigurowanie obiektu ObjectDataSource do używania ProductsBLLGetProductsByCategoryID(categoryID) metody klasy (kliknij, aby wyświetlić obraz pełnowymiarowy)

GetProductsByCategoryID(categoryID) Ponieważ metoda akceptuje parametr wejściowy (categoryID), kreator Wybieranie źródła danych oferuje nam możliwość określenia źródła parametru. Ustaw źródło parametru na QueryString przy użyciu pola QueryStringField CategoryID.

Użyj identyfikatora CategoryID pola zapytania jako źródła parametru

Rysunek 5. Użyj pola CategoryID zapytania jako źródła parametru (kliknij, aby wyświetlić obraz pełnowymiarowy)

Jak pokazano w poprzednich samouczkach, po ukończeniu pracy kreatora Wybieranie źródła danych program Visual Studio automatycznie tworzy dla ItemTemplate listy danych listę danych zawierającą każdą nazwę i wartość pola danych. Zastąp ten szablon tylko nazwą, dostawcą i ceną produktu. Ustaw również właściwość DataList RepeatColumns na 2. Po tych zmianach znaczniki deklaratywne elementu DataList i ObjectDataSource powinny wyglądać podobnie do następujących:

<asp:DataList ID="ProductsInCategory" runat="server" DataKeyField="ProductID"
    RepeatColumns="2" DataSourceID="ProductsInCategoryDataSource"
    EnableViewState="False">
    <ItemTemplate>
        <h5><%# Eval("ProductName") %></h5>
        <p>
            Supplied by <%# Eval("SupplierName") %><br />
            <%# Eval("UnitPrice", "{0:C}") %>
        </p>
    </ItemTemplate>
</asp:DataList>
 
<asp:ObjectDataSource ID="ProductsInCategoryDataSource"
    OldValuesParameterFormatString="original_{0}" runat="server"
    SelectMethod="GetProductsByCategoryID" TypeName="ProductsBLL">
    <SelectParameters>
        <asp:QueryStringParameter Name="categoryID" QueryStringField="CategoryID"
            Type="Int32" />
    </SelectParameters>
</asp:ObjectDataSource>

Aby wyświetlić tę stronę w akcji, zacznij od CategoryListMaster.aspx strony. Następnie kliknij link na liście punktowanej kategorii. Spowoduje to przejście do ProductsForCategoryDetails.aspxelementu , przechodząc przez CategoryID ciąg zapytania. Obiekt ProductsInCategoryDataSource ObjectDataSource w pliku ProductsForCategoryDetails.aspx pobierze wtedy tylko te produkty dla określonej kategorii i wyświetli je w tabeli DataList, która renderuje dwa produkty na wiersz. Rysunek 6 przedstawia zrzut ekranu przedstawiający ProductsForCategoryDetails.aspx wyświetlanie napojów.

Napoje są wyświetlane, dwa na wiersz

Rysunek 6. Napoje są wyświetlane, dwa na wiersz (kliknij, aby wyświetlić obraz pełnowymiarowy)

Krok 4. Wyświetlanie informacji o kategorii na ProductsForCategoryDetails.aspx

Gdy użytkownik kliknie kategorię w programie CategoryListMaster.aspx, zostanie przeniesiony do ProductsForCategoryDetails.aspx i wyświetlonych produktów należących do wybranej kategorii. Jednak w obszarze ProductsForCategoryDetails.aspx nie ma żadnych wskazówek wizualnych co do wybranej kategorii. Użytkownik, który miał kliknąć napoje, ale przypadkowo kliknął Condiments, nie ma sposobu na uświadomienie sobie błędu po osiągnięciu ProductsForCategoryDetails.aspx. Aby złagodzić ten potencjalny problem, możemy wyświetlić informacje o wybranej kategorii — jej nazwie i opisie ProductsForCategoryDetails.aspx — w górnej części strony.

Aby to osiągnąć, dodaj kontrolkę FormView nad kontrolką Repeater w elemencie ProductsForCategoryDetails.aspx. Następnie dodaj nową wartość ObjectDataSource do strony z tagu inteligentnego kontrolki FormView o nazwie CategoryDataSource i skonfiguruj ją tak, aby korzystała GetCategoryByCategoryID(categoryID) z CategoriesBLL metody klasy.

Uzyskiwanie dostępu do informacji o kategorii za pomocą metody GetCategoryByCategoryID(categoryID) klasy CategoryBLL

Rysunek 7. Uzyskiwanie dostępu do informacji o kategorii za pomocą CategoriesBLL metody Klasy GetCategoryByCategoryID(categoryID) (kliknij, aby wyświetlić obraz pełnowymiarowy)

Podobnie jak w przypadku elementu ObjectDataSource dodanego ProductsInCategoryDataSource w kroku 3, CategoryDataSourcekreator "Konfigurowanie źródła danych" wyświetli nam monit o podanie źródła parametru wejściowego GetCategoryByCategoryID(categoryID) metody. Użyj dokładnie tych samych ustawień co poprzednio, ustawiając źródło parametru na QueryString i wartość CategoryID QueryStringField na (wróć do rysunku 5).

Po ukończeniu pracy kreatora program Visual Studio automatycznie tworzy element ItemTemplate, EditItemTemplatei InsertItemTemplate dla elementu FormView. Ponieważ udostępniamy interfejs tylko do odczytu, możesz usunąć element EditItemTemplate i InsertItemTemplate. Ponadto możesz dostosować element FormView.ItemTemplate Po usunięciu nadmiarowych szablonów i dostosowaniu elementu ItemTemplate znaczniki deklaratywne formView i ObjectDataSource powinny wyglądać podobnie do następujących:

<asp:FormView ID="FormView1" runat="server" DataKeyNames="CategoryID"
    DataSourceID="CategoryDataSource" EnableViewState="False" Width="100%">
    <ItemTemplate>
        <h3>
            <asp:Label ID="CategoryNameLabel" runat="server"
                Text='<%# Bind("CategoryName") %>' />
        </h3>
        <p>
            <asp:Label ID="DescriptionLabel" runat="server"
                Text='<%# Bind("Description") %>' />
        </p>
    </ItemTemplate>
</asp:FormView>
 
<asp:ObjectDataSource ID="CategoryDataSource" runat="server"
    OldValuesParameterFormatString="original_{0}"
    SelectMethod="GetCategoryByCategoryID" TypeName="CategoriesBLL">
    <SelectParameters>
        <asp:QueryStringParameter Name="categoryID" Type="Int32"
            QueryStringField="CategoryID" />
    </SelectParameters>
</asp:ObjectDataSource>

Rysunek 8 przedstawia zrzut ekranu podczas wyświetlania tej strony za pośrednictwem przeglądarki.

Uwaga

Oprócz widoku FormView dodano również kontrolkę HyperLink nad kontrolką FormView, która spowoduje powrót użytkownika do listy kategorii (CategoryListMaster.aspx). Możesz umieścić ten link gdzie indziej lub całkowicie pominąć go.

Informacje o kategorii są teraz wyświetlane w górnej części strony

Rysunek 8. Informacje o kategorii są teraz wyświetlane w górnej części strony (kliknij, aby wyświetlić obraz pełnowymiarowy)

Krok 5. Wyświetlanie komunikatu, jeśli żadne produkty nie należą do wybranej kategorii

Strona CategoryListMaster.aspx zawiera listę wszystkich kategorii w systemie, niezależnie od tego, czy istnieją jakiekolwiek skojarzone produkty. Jeśli użytkownik kliknie kategorię bez skojarzonych produktów, element DataList w ProductsForCategoryDetails.aspx pliku nie zostanie renderowany, ponieważ jego źródło danych nie będzie zawierać żadnych elementów. Jak widzieliśmy w poprzednich samouczkach, kontrolka GridView udostępnia EmptyDataText właściwość, która może służyć do określania komunikatu tekstowego do wyświetlenia, jeśli w źródle danych nie ma żadnych rekordów. Niestety, ani DataList, ani Repeater nie ma takiej właściwości.

Aby wyświetlić komunikat informujący użytkownika, że nie ma pasujących produktów dla wybranej kategorii, musimy dodać kontrolkę Etykieta do strony, której Text właściwość ma przypisaną wiadomość do wyświetlenia w przypadku braku pasujących produktów. Następnie musimy programowo ustawić jej Visible właściwość na podstawie tego, czy element DataList zawiera jakiekolwiek elementy.

Aby to osiągnąć, zacznij od dodania etykiety poniżej listy DataList. Ustaw jej ID właściwość na NoProductsMessage i jej Text właściwość na "Brak produktów dla wybranej kategorii..." Następnie należy programowo ustawić właściwość etykiety Visible na podstawie tego, czy jakiekolwiek dane zostały powiązane z listą ProductsInCategory Danych. To przypisanie musi zostać wykonane po powiązaniu danych z listą Danych. W przypadku kontrolek GridView, DetailsView i FormView można utworzyć procedurę obsługi zdarzeń dla zdarzenia kontrolki DataBound , która jest uruchamiana po zakończeniu łączenia danych. Jednak ani DataList, ani Repeater nie ma dostępnego DataBound zdarzenia.

W tym konkretnym przykładzie możemy przypisać właściwość Label Visible w procedurze Page_Load obsługi zdarzeń, ponieważ dane zostaną przypisane do listy DataList przed zdarzeniem strony Load . Jednak takie podejście nie będzie działać w ogólnym przypadku, ponieważ dane z obiektu ObjectDataSource mogą być powiązane z listą DataList w dalszej części cyklu życia strony. Jeśli na przykład wyświetlane dane są oparte na wartości w innej kontrolce, takiej jak podczas wyświetlania raportu głównego/szczegółowego przy użyciu listy DropDownList do przechowywania rekordów "master", dane mogą nie zostać odbicia do kontrolki sieci Web danych do PreRender momentu etapu w cyklu życia strony.

Jednym z rozwiązań, które będzie działać we wszystkich przypadkach, jest przypisanie właściwości do False elementu w procedurze obsługi zdarzeń DataList ItemDataBound (lub ItemCreated) podczas tworzenia powiązania typu Item elementu lub AlternatingItem.Visible W takim przypadku wiemy, że w źródle danych znajduje się co najmniej jeden element danych i dlatego może ukryć etykietę NoProductsMessage . Oprócz tej procedury obsługi zdarzeń potrzebujemy również procedury obsługi zdarzeń dla zdarzenia DataList DataBinding , gdzie inicjujemy właściwość Label Visible na Truewartość . DataBinding Ponieważ zdarzenie jest uruchamiane przed ItemDataBound zdarzeniami, właściwość Etykieta Visible zostanie początkowo ustawiona na Truewartość . Jeśli jednak istnieją jakiekolwiek elementy danych, zostanie ustawiona wartość False. Poniższy kod implementuje tę logikę:

protected void ProductsInCategory_DataBinding(object sender, EventArgs e)
{
    // Show the Label
    NoProductsMessage.Visible = true;
}
 
protected void ProductsInCategory_ItemDataBound(object sender, DataListItemEventArgs e)
{
    // If we have a data item, hide the Label
    if (e.Item.ItemType == ListItemType.Item ||
        e.Item.ItemType == ListItemType.AlternatingItem)
        NoProductsMessage.Visible = false;
}

Wszystkie kategorie w bazie danych Northwind są skojarzone z co najmniej jednym produktem. Aby przetestować tę funkcję, ręcznie dostosowano bazę danych Northwind na potrzeby tego samouczka, ponownie przypisując wszystkie produkty skojarzone z kategorią Produkcja (CategoryID = 7) do kategorii Owoce morza (CategoryID = 8). Można to zrobić w Eksploratorze serwera, wybierając pozycję Nowe zapytanie i używając następującej UPDATE instrukcji:

UPDATE Products SET
    CategoryID = 8
WHERE CategoryID = 7

Po zaktualizowaniu bazy danych wróć do CategoryListMaster.aspx strony i kliknij link Utwórz. Ponieważ nie ma już żadnych produktów należących do kategorii Produkcja, powinien zostać wyświetlony komunikat "Brak produktów dla wybranej kategorii..." komunikat, jak pokazano na rysunku 9.

Komunikat jest wyświetlany, jeśli nie ma produktów należących do wybranej kategorii

Rysunek 9. Komunikat jest wyświetlany, jeśli nie ma produktów należących do wybranej kategorii (kliknij, aby wyświetlić obraz pełnowymiarowy)

Podsumowanie

Chociaż raporty wzorca/szczegółów mogą wyświetlać zarówno rekordy główne, jak i szczegółowe na jednej stronie, w wielu witrynach sieci Web są rozdzielane między dwie strony sieci Web. W tym samouczku przyjrzeliśmy się, jak zaimplementować taki raport główny/szczegółowy, mając kategorie wymienione na liście punktowanej przy użyciu repeatera na stronie internetowej "master" i skojarzonych produktów wymienionych na stronie "szczegóły". Każdy element listy na stronie wzorcowej sieci Web zawiera link do strony szczegółów, która została przekazana CategoryID wraz z wartością wiersza.

Na stronie szczegółów pobieranie tych produktów dla określonego dostawcy zostało wykonane za pomocą ProductsBLL metody klasy GetProductsByCategoryID(categoryID) . Wartość categoryID parametru CategoryID została określona deklaratywnie przy użyciu wartości querystring jako źródła parametrów. Przyjrzeliśmy się również sposobom wyświetlania szczegółów kategorii na stronie szczegółów przy użyciu kontrolki FormView i wyświetlaniu komunikatu, jeśli nie ma produktów należących do wybranej kategorii.

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 do niego dotrzeć pod adresem mitchell@4GuysFromRolla.com. Lub za pośrednictwem swojego bloga, który można znaleźć na stronie http://ScottOnWriting.NET.

Specjalne podziękowania...

Ta seria samouczków została przejrzyona przez wielu przydatnych recenzentów. Głównymi recenzentami tego samouczka byli Zack Jones i Liz Shulok. Chcesz przejrzeć nadchodzące artykuły MSDN? Jeśli tak, upuść mi wiersz pod adresemmitchell@4GuysFromRolla.com .