Formularz rekord główny/szczegóły korzystający z listy punktowanej rekordów głównych z kontrolką DataList szczegółów (C#)

Autor: Scott Mitchell

Pobierz plik PDF

W tym samouczku skompresujemy dwustronicowy raport wzorcowy/szczegółowy poprzedniego samouczka na jedną stronę, pokazując punktowaną listę nazw kategorii po lewej stronie ekranu i produkty wybranej kategorii po prawej stronie ekranu.

Wprowadzenie

W poprzednim samouczku przyjrzeliśmy się, jak oddzielić raport wzorca/szczegółów na dwóch stronach. Na stronie wzorcowej użyliśmy kontrolki Repeater do renderowania listy punktowanej kategorii. Każda nazwa kategorii to hiperłącze, które po kliknięciu spowoduje przejście użytkownika do strony szczegółów, gdzie dwukolumna lista danych pokazała te produkty należące do wybranej kategorii.

W tym samouczku skompresujemy dwustronicowy samouczek na jedną stronę, pokazując punktowaną listę nazw kategorii po lewej stronie ekranu z każdą nazwą kategorii renderowaną jako LinkButton. Kliknięcie jednej z nazw kategorii LinkButtons powoduje powrót i powiązanie wybranych produktów kategorii z dwukolumnową listą danych po prawej stronie ekranu. Oprócz wyświetlania nazwy każdej kategorii, repeater po lewej stronie pokazuje, ile łącznych produktów istnieje dla danej kategorii (zobacz Rysunek 1).

Nazwa kategorii i łączna liczba produktów są wyświetlane po lewej stronie

Rysunek 1. Nazwa kategorii i całkowita liczba produktów są wyświetlane po lewej stronie (kliknij, aby wyświetlić obraz pełnowymiarowy)

Krok 1. Wyświetlanie repeatera w lewej części ekranu

Na potrzeby tego samouczka musimy wyświetlić listę punktowaną kategorii po lewej stronie wybranych produktów kategorii. Zawartość na stronie internetowej można umieścić przy użyciu standardowych tagów akapitów elementów HTML, spacji niełamających się, <table> s itd. lub za pomocą technik kaskadowego arkusza stylów (CSS). Wszystkie nasze samouczki do tej pory używały technik CSS do pozycjonowania. Podczas tworzenia interfejsu użytkownika nawigacji na naszej stronie wzorcowej w samouczku Strony wzorcowe i Nawigacja po witrynie użyliśmy bezwzględnego pozycjonowania, co wskazuje dokładne przesunięcie pikseli dla listy nawigacji i zawartości głównej. Możesz też użyć css, aby umieścić jeden element w prawo lub w lewo od innego przez zmienną. Możemy wyświetlić listę punktowaną kategorii po lewej stronie wybranych produktów kategorii, unosząc repeater z lewej strony listy Danych

CategoriesAndProducts.aspx Otwórz stronę z DataListRepeaterFiltering folderu i dodaj ją do strony Repeater i DataList. Ustaw wartość s repeater na IDCategories i wartość DataList s na CategoryProductswartość . Przejdź do widoku Źródło i umieść kontrolki Repeater i DataList we własnych <div> elementach. Oznacza to, że najpierw ujęj element Repeater w <div> element, a następnie element DataList we własnym <div> elemencie bezpośrednio po repeaterze. Znaczniki w tym momencie powinny wyglądać podobnie do następujących:

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

Aby unosić element Repeater po lewej stronie listy danych, musimy użyć atrybutu float stylu CSS, w następujący sposób:

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

Zmiennoprzecinkowy float: left; pierwszy <div> element po lewej stronie drugiego elementu. Ustawienia width i padding-right wskazują pierwszy <div>width s i ile jest dodawane dopełnienie między zawartością <div> elementu a prawym marginesem. Aby uzyskać więcej informacji na temat elementów zmiennoprzecinkowych w arkuszu CSS, zobacz Floatutorial.

Zamiast określać ustawienie stylu bezpośrednio za pomocą pierwszego <p> atrybutu elementu style , zamiast tego utwórzmy nową klasę CSS o Styles.css nazwie FloatLeft:

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

Następnie możemy zamienić element <div> na <div class="FloatLeft">.

Po dodaniu klasy CSS i skonfigurowaniu znaczników na CategoriesAndProducts.aspx stronie przejdź do Projektant. Powinna zostać wyświetlona zmienna Repeater po lewej stronie listy Danych (chociaż teraz obie są wyświetlane jako szare pola, ponieważ jeszcze skonfigurowaliśmy źródła danych lub szablony).

Repeater jest zmiennoprzecinkowy po lewej stronie listy danych

Rysunek 2. Repeater jest zmiennoprzecinkowy po lewej stronie listy danych (kliknij, aby wyświetlić obraz pełnowymiarowy)

Krok 2. Określanie liczby produktów dla każdej kategorii

Po zakończeniu znaczników repeater i DataList możemy powiązać dane kategorii z kontrolką Repeater. Jednak w miarę wyświetlania listy punktowanej kategorii na rysunku 1 oprócz nazwy każdej kategorii musimy również wyświetlić liczbę produktów skojarzonych z kategorią. Aby uzyskać dostęp do tych informacji, możemy:

  • Określ te informacje z klasy ASP.NET strony kod-za. Biorąc pod uwagę konkretne categoryID dane, możemy określić liczbę skojarzonych produktów przez wywołanie ProductsBLL metody klasy .GetProductsByCategoryID(categoryID) Ta metoda zwraca ProductsDataTable obiekt, którego Count właściwość wskazuje, ile ProductsRow istnieje, czyli liczbę produktów dla określonego categoryIDobiektu . Możemy utworzyć procedurę obsługi zdarzeń ItemDataBound dla repeatera, która dla każdej kategorii powiązanej z repeater wywołuje ProductsBLL metodę klasy s GetProductsByCategoryID(categoryID) i zawiera jej liczbę w danych wyjściowych.
  • Zaktualizuj element CategoriesDataTable w typowym zestawie danych, aby uwzględnić kolumnę NumberOfProducts . Następnie możemy zaktualizować metodę GetCategories() w pliku , CategoriesDataTable aby uwzględnić te informacje lub, alternatywnie, pozostawić GetCategories() jako i utworzyć nową CategoriesDataTable metodę o nazwie GetCategoriesAndNumberOfProducts().

Przyjrzyjmy się obu tym technikom. Pierwsze podejście jest prostsze do zaimplementowania, ponieważ nie musimy aktualizować warstwy dostępu do danych; jednak wymaga więcej komunikacji z bazą danych. Wywołanie ProductsBLL metody klasy w GetProductsByCategoryID(categoryID) procedurze obsługi zdarzeń ItemDataBound dodaje dodatkowe wywołanie bazy danych dla każdej kategorii wyświetlanej w repeaterze. W przypadku tej techniki istnieją wywołania bazy danych N + 1, gdzie N jest liczbą kategorii wyświetlanych w repeater. Przy drugim podejściu liczba produktów jest zwracana z informacjami o każdej kategorii z CategoriesBLL metody klasy s GetCategories() (lub GetCategoriesAndNumberOfProducts()), co powoduje tylko jedną podróż do bazy danych.

Określanie liczby produktów w procedurze obsługi zdarzeń ItemDataBound

Określenie liczby produktów dla każdej kategorii w procedurze obsługi zdarzeń repeatera ItemDataBound nie wymaga żadnych modyfikacji istniejącej warstwy dostępu do danych. Wszystkie modyfikacje można wprowadzić bezpośrednio na CategoriesAndProducts.aspx stronie. Zacznij od dodania nowego obiektu ObjectDataSource o nazwie CategoriesDataSource za pośrednictwem tagu inteligentnego Repeater s. Następnie skonfiguruj obiekt CategoriesDataSource ObjectDataSource tak, aby pobierał swoje dane z CategoriesBLL metody klasy s GetCategories() .

Konfigurowanie obiektu ObjectDataSource do używania metody GetCategories() klasy CategoryBLL

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

Każdy element w repeaterze musi być klikalny i po kliknięciu Categories powoduje CategoryProducts wyświetlenie tych produktów dla wybranej kategorii przez listę danych. Można to osiągnąć, tworząc hiperlink z każdej kategorii, łącząc z powrotem z tą samą stroną (CategoriesAndProducts.aspx), ale przechodząc CategoryID przez ciąg zapytania, podobnie jak w poprzednim samouczku. Zaletą tego podejścia jest to, że strona wyświetlającą określone produkty kategorii może być zakładkami i indeksowana przez wyszukiwarkę.

Alternatywnie możemy utworzyć każdą kategorię LinkButton, czyli podejście, którego użyjemy w tym samouczku. Element LinkButton renderuje się w przeglądarce użytkownika jako hiperłącze, ale po kliknięciu powoduje powrót; po powrocie po awarii należy odświeżyć element ObjectDataSource elementu DataList, aby wyświetlić te produkty należące do wybranej kategorii. W tym samouczku użycie hiperlinku ma większe znaczenie niż użycie elementu LinkButton; jednak mogą istnieć inne scenariusze, w których użycie elementu LinkButton jest bardziej korzystne. Chociaż podejście hiperlinku byłoby idealne w tym przykładzie, przyjrzyjmy się zamiast tego metodzie LinkButton. Jak zobaczymy, użycie elementu LinkButton wprowadza pewne wyzwania, które w przeciwnym razie nie powstałyby z hiperlinkiem. W związku z tym użycie elementu LinkButton w tym samouczku spowoduje wyróżnienie tych wyzwań i pomoc w dostarczaniu rozwiązań dla tych scenariuszy, w których możemy użyć elementu LinkButton zamiast hiperłącza.

Uwaga

Zachęcamy do powtórzenia tego samouczka przy użyciu kontrolki lub <a> elementu funkcji HyperLink zamiast elementu LinkButton.

Na poniższej adiustacji przedstawiono składnię deklaratywną dla repeatera i objectDataSource. Należy pamiętać, że szablony repeater renderuje listę punktowaną z każdym elementem jako element LinkButton:

<asp:Repeater ID="Categories" runat="server" DataSourceID="CategoriesDataSource">
    <HeaderTemplate>
        <ul>
    </HeaderTemplate>
    <ItemTemplate>
        <li><asp:LinkButton runat="server" ID="ViewCategory" /></li>
    </ItemTemplate>
    <FooterTemplate>
        </ul>
    </FooterTemplate>
</asp:Repeater>
<asp:ObjectDataSource ID="CategoriesDataSource" runat="server"
    OldValuesParameterFormatString="original_{0}"
    SelectMethod="GetCategories" TypeName="CategoriesBLL">
</asp:ObjectDataSource>

Uwaga

W tym samouczku moduł powtarzający musi mieć włączony stan widoku (zwróć uwagę na pominięcie EnableViewState="False" składni deklaratywnej repeatera). W kroku 3 utworzymy procedurę obsługi zdarzeń dla zdarzenia repeateraItemCommand, w którym będziemy aktualizować kolekcję ObjectDataSource biblioteki DataList.SelectParameters Funkcja Repeater ItemCommandnie zostanie jednak wyzwolona, jeśli stan widoku jest wyłączony.

Element LinkButton z wartością ID właściwości nie ma ustawionej ViewCategory właściwości Text . Gdybyśmy chcieli po prostu wyświetlić nazwę kategorii, ustawilibyśmy właściwość Text deklaratywnie za pomocą składni łączenia danych, w następujący sposób:

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

Chcemy jednak pokazać zarówno nazwę kategorii , jak i liczbę produktów należących do tej kategorii. Te informacje można pobrać z procedury obsługi zdarzeń repeatera ItemDataBound , wykonując wywołanie ProductBLL metody s GetCategoriesByProductID(categoryID) klasy i określając liczbę rekordów zwracanych w wynikowym ProductsDataTablekodzie, jak pokazano w poniższym kodzie:

protected void Categories_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
    // Make sure we're working with a data item...
    if (e.Item.ItemType == ListItemType.Item ||
        e.Item.ItemType == ListItemType.AlternatingItem)
    {
        // Reference the CategoriesRow instance bound to this RepeaterItem
        Northwind.CategoriesRow category =
            (Northwind.CategoriesRow) ((System.Data.DataRowView) e.Item.DataItem).Row;
        // Determine how many products are in this category
        NorthwindTableAdapters.ProductsTableAdapter productsAPI =
            new NorthwindTableAdapters.ProductsTableAdapter();
        int productCount =
            productsAPI.GetProductsByCategoryID(category.CategoryID).Count;
        // Reference the ViewCategory LinkButton and set its Text property
        LinkButton ViewCategory = (LinkButton)e.Item.FindControl("ViewCategory");
        ViewCategory.Text =
            string.Format("{0} ({1:N0})", category.CategoryName, productCount);
    }
}

Zaczynamy od upewnienia się, że pracujemy z elementem danych (takim, którego ItemType element jest Item lub AlternatingItem), a następnie odwołujemy się CategoriesRow do wystąpienia, które właśnie zostało powiązane z bieżącym RepeaterItemelementem . Następnie określamy liczbę produktów dla tej kategorii, tworząc wystąpienie ProductsBLL klasy, wywołując jej GetCategoriesByProductID(categoryID) metodę i określając liczbę rekordów zwracanych przy użyciu Count właściwości . ViewCategory Na koniec właściwość LinkButton w elemencie ItemTemplate jest przywoływana, a jej Text właściwość ma wartość CategoryName (NumberOfProductsInCategory), gdzie parametr NumberOfProductsInCategory jest sformatowany jako liczba z zerowymi miejscami dziesiętnymi.

Uwaga

Alternatywnie możemy dodać funkcję formatowania do klasy ASP.NET s page-behind, która akceptuje wartości CategoryName kategorii i CategoryID zwraca CategoryName wartość połączoną z liczbą produktów w kategorii (określona przez wywołanie GetCategoriesByProductID(categoryID) metody). Wyniki takiej funkcji formatowania można deklaratywnie przypisać do właściwości Text elementu LinkButton, zastępując potrzebę obsługi zdarzeń ItemDataBound . Aby uzyskać więcej informacji na temat używania funkcji formatowania, zapoznaj się z tematem Using TemplateFields in the GridView Control (Używanie pól szablonów w kontrolce GridView) lub formatowaniu samouczków DataList i Repeater Based On Data (Powtarzanie na podstawie danych na podstawie danych), aby uzyskać więcej informacji na temat używania funkcji formatowania.

Po dodaniu tej procedury obsługi zdarzeń poświęć chwilę, aby przetestować stronę za pośrednictwem przeglądarki. Zwróć uwagę, jak każda kategoria znajduje się na liście punktowanej, wyświetlając nazwę kategorii i liczbę produktów skojarzonych z kategorią (zobacz Rysunek 4).

Każda nazwa kategorii i liczba produktów są wyświetlane

Rysunek 4. Wyświetlane są nazwy każdej kategorii i liczba produktów (kliknij, aby wyświetlić obraz pełnowymiarowy)

Aktualizowanie elementuCategoriesDataTableiCategoriesTableAdapterw celu uwzględnienia liczby produktów dla każdej kategorii

Zamiast określać liczbę produktów dla każdej kategorii powiązanej z repeaterem, możemy usprawnić ten proces, dostosowując CategoriesDataTable element i CategoriesTableAdapter w warstwie dostępu do danych, aby uwzględnić te informacje natywnie. Aby to osiągnąć, musimy dodać nową kolumnę, aby CategoriesDataTable przechowywać liczbę skojarzonych produktów. Aby dodać nową kolumnę do tabeli DataTable, otwórz typowy zestaw danych (App_Code\DAL\Northwind.xsd), kliknij prawym przyciskiem myszy tabelę danych, aby zmodyfikować, a następnie wybierz pozycję Dodaj/Kolumnę. Dodaj nową kolumnę do elementu CategoriesDataTable (zobacz Rysunek 5).

Dodawanie nowej kolumny do kategoriiDataSource

Rysunek 5. Dodawanie nowej kolumny do elementu CategoriesDataSource (kliknij, aby wyświetlić obraz pełnowymiarowy)

Spowoduje to dodanie nowej kolumny o nazwie Column1, którą można zmienić, wpisując po prostu inną nazwę. Zmień nazwę tej nowej kolumny na NumberOfProducts. Następnie musimy skonfigurować właściwości tej kolumny. Kliknij nową kolumnę i przejdź do okno Właściwości. Zmień właściwość kolumny DataType z na System.StringSystem.Int32 i ustaw ReadOnly właściwość na True, jak pokazano na rysunku 6.

Ustawianie właściwości DataType i ReadOnly nowej kolumny

Rysunek 6. Ustawianie DataType właściwości i ReadOnly nowej kolumny

Chociaż kolumna CategoriesDataTable ma teraz kolumnę NumberOfProducts , jej wartość nie jest ustawiana przez żadne z odpowiednich zapytań TableAdapter. Możemy zaktualizować metodę GetCategories() , aby zwrócić te informacje, jeśli chcemy, aby takie informacje zwracane za każdym razem, gdy są pobierane informacje o kategorii. Jeśli jednak musimy chwycić tylko liczbę skojarzonych produktów dla kategorii w rzadkich przypadkach (takich jak tylko w tym samouczku), możemy pozostawić GetCategories() jako i utworzyć nową metodę zwracającą te informacje. Użyjmy tego ostatniego podejścia, tworząc nową metodę o nazwie GetCategoriesAndNumberOfProducts().

Aby dodać tę nową GetCategoriesAndNumberOfProducts() metodę, kliknij prawym przyciskiem CategoriesTableAdapter myszy polecenie i wybierz pozycję Nowe zapytanie. Spowoduje to wyświetlenie Kreatora konfiguracji zapytań TableAdapter, którego używaliśmy wiele razy w poprzednich samouczkach. W przypadku tej metody uruchom kreatora, wskazując, że zapytanie używa instrukcji AD-hoc SQL zwracającej wiersze.

Tworzenie metody przy użyciu instrukcji AD-Hoc SQL

Rysunek 7. Tworzenie metody przy użyciu instrukcji AD-Hoc SQL (kliknij, aby wyświetlić obraz pełnowymiarowy)

Instrukcja SQL zwraca wiersze

Rysunek 8. Instrukcja SQL zwraca wiersze (kliknij, aby wyświetlić obraz pełnowymiarowy)

Na następnym ekranie kreatora zostanie wyświetlony monit o użycie zapytania. Aby zwrócić każdą kategorię s CategoryID, CategoryNamei Description pola wraz z liczbą produktów skojarzonych z kategorią, użyj następującej SELECT instrukcji:

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

Określanie zapytania do użycia

Rysunek 9. Określanie zapytania do użycia (kliknij, aby wyświetlić obraz pełnowymiarowy)

Należy pamiętać, że podqueria, która oblicza liczbę produktów skojarzonych z kategorią, jest aliasowana jako NumberOfProducts. To dopasowanie nazewnictwa powoduje, że wartość zwrócona przez tę podquerię ma być skojarzona z kolumną CategoriesDataTable s NumberOfProducts .

Po wprowadzeniu tego zapytania ostatnim krokiem jest wybranie nazwy nowej metody. Użyj FillWithNumberOfProducts wartości i GetCategoriesAndNumberOfProducts dla opcji Wypełnij tabelę danych i zwróć odpowiednio wzorce DataTable.

Nazwij nowe metody TableAdapter FillWithNumberOfProducts i GetCategoriesAndNumberOfProducts

Rysunek 10. Nadaj nowej nazwie metody FillWithNumberOfProducts TableAdapter i GetCategoriesAndNumberOfProducts (kliknij, aby wyświetlić obraz pełnowymiarowy)

W tym momencie warstwa dostępu do danych została rozszerzona, aby uwzględnić liczbę produktów na kategorię. Ponieważ cała nasza warstwa prezentacji kieruje wszystkie wywołania do dal za pomocą oddzielnej warstwy logiki biznesowej, musimy dodać odpowiednią GetCategoriesAndNumberOfProducts metodę do CategoriesBLL klasy:

[System.ComponentModel.DataObjectMethodAttribute
    (System.ComponentModel.DataObjectMethodType.Select, false)]
public Northwind.CategoriesDataTable GetCategoriesAndNumberOfProducts()
{
    return Adapter.GetCategoriesAndNumberOfProducts();
}

Po zakończeniu dal i BLL jesteśmy gotowi powiązać te dane z Categories repeater w programie CategoriesAndProducts.aspx! Jeśli element ObjectDataSource dla repeatera został już utworzony z sekcji Określanie liczby produktów w ItemDataBound programie obsługi zdarzeń, usuń to ustawienie właściwości ObjectDataSource i usuń ustawienie właściwości Repeater, DataSourceID a także odszyfruj zdarzenie Repeater z ItemDataBound programu obsługi zdarzeń, usuwając składnię Handles Categories.OnItemDataBound w klasie ASP.NET kod-behind.

Po powrocie do oryginalnego stanu repeater dodaj nowy obiektDataSource o nazwie CategoriesDataSource za pośrednictwem tagu inteligentnego Repeater s. Skonfiguruj obiekt ObjectDataSource do używania CategoriesBLL klasy, ale zamiast używać GetCategories()GetCategoriesAndNumberOfProducts() metody , użyj jej zamiast tego (zobacz Rysunek 11).

Konfigurowanie obiektu ObjectDataSource do używania metody GetCategoriesAndNumberOfProducts

Rysunek 11. Konfigurowanie obiektu ObjectDataSource do użycia GetCategoriesAndNumberOfProducts metody (kliknij, aby wyświetlić obraz pełnowymiarowy)

Następnie zaktualizuj ItemTemplate właściwość , tak aby właściwość LinkButton Text została deklaracyjnie przypisana przy użyciu składni powiązania danych i zawiera pola CategoryName danych i NumberOfProducts . Kompletny deklaratywny znacznik dla repeatera i CategoriesDataSource obiektuDataSource następuje:

<asp:Repeater ID="Categories" runat="server" DataSourceID="CategoriesDataSource">
    <HeaderTemplate>
        <ul>
    </HeaderTemplate>
    <ItemTemplate>
        <li><asp:LinkButton runat="server" ID="ViewCategory"
                Text='<%# String.Format("{0} ({1:N0})", _
                    Eval("CategoryName"), Eval("NumberOfProducts")) %>' />
        </li>
    </ItemTemplate>
    <FooterTemplate>
        </ul>
    </FooterTemplate>
</asp:Repeater>
<asp:ObjectDataSource ID="CategoriesDataSource" runat="server"
    OldValuesParameterFormatString="original_{0}"
    SelectMethod="GetCategoriesAndNumberOfProducts" TypeName="CategoriesBLL">
</asp:ObjectDataSource>

Dane wyjściowe renderowane przez zaktualizowanie dal w celu uwzględnienia NumberOfProducts kolumny są takie same jak przy użyciu ItemDataBound podejścia obsługi zdarzeń (wróć do rysunku 4, aby zobaczyć zrzut ekranu repeatera pokazujący nazwy kategorii i liczbę produktów).

Krok 3. Wyświetlanie produktów wybranej kategorii

W tym momencie mamy Categories repeater wyświetlający listę kategorii wraz z liczbą produktów w każdej kategorii. Repeater używa elementu LinkButton dla każdej kategorii, która po kliknięciu powoduje powrót, w którym momencie musimy wyświetlić te produkty dla wybranej kategorii na liście CategoryProducts Danych.

Jednym z wyzwań stojących przed nami jest sposób wyświetlania tylko tych produktów dla wybranej kategorii. W samouczku Master/Detail Using a Selectable Master GridView with a DetailsView (Szczegóły) pokazano, jak utworzyć element GridView, którego wiersze można wybrać, z wybranymi szczegółami wiersza wyświetlanymi w widoku DetailsView na tej samej stronie. Obiekt ObjectDataSource obiektu GridView zwrócił informacje o wszystkich produktach przy użyciu ProductsBLL metody s GetProducts() , podczas gdy element DetailsView s ObjectDataSource pobrał informacje o wybranym produkcie przy użyciu GetProductsByProductID(productID) metody . Wartość parametru productID została podana deklaratywnie przez skojarzenie jej z wartością właściwości GridView.SelectedValue Niestety, repeater nie ma SelectedValue właściwości i nie może służyć jako źródło parametrów.

Uwaga

Jest to jedno z tych wyzwań, które pojawiają się podczas korzystania z elementu LinkButton w repeaterze. Gdyby zamiast tego użyliśmy hiperlinku do CategoryID przekazywania przez ciąg zapytania, możemy użyć tego pola QueryString jako źródła wartości parametru.

Zanim jednak martwimy się o brak właściwości repeatera, najpierw powiążmy SelectedValue listę danych z obiektem ObjectDataSource i określmy jego ItemTemplatewartość .

Z tagu inteligentnego DataList wybierz opcję dodania nowego obiektu ObjectDataSource o nazwie CategoryProductsDataSource i skonfigurowania go do używania ProductsBLL metody s GetProductsByCategoryID(categoryID) klasy. Ponieważ lista DataList w tym samouczku oferuje interfejs tylko do odczytu, możesz ustawić listy rozwijane na karcie INSERT, UPDATE i DELETE na wartość (Brak).

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

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

GetProductsByCategoryID(categoryID) Ponieważ metoda oczekuje parametru wejściowego (categoryID), Kreator konfigurowania źródła danych umożliwia określenie źródła parametru. Jeśli kategorie zostały wymienione w kontrolce GridView lub DataList, ustawiliśmy listę rozwijaną Źródło parametru na Kontrolkę i ControlID ID kontrolki sieci Web danych. Jednak ponieważ repeater nie ma SelectedValue właściwości, której nie można użyć jako źródła parametrów. Jeśli to sprawdzisz, zobaczysz, że lista rozwijana ControlID zawiera tylko jedną kontrolkę ID``CategoryProducts, z ID listy DanychList.

Na razie ustaw listę rozwijaną Źródło parametru na Wartość Brak. Zakończymy programowe przypisywanie tej wartości parametru po kliknięciu kategorii LinkButton w repeaterze.

Nie określaj źródła parametrów dla parametru categoryID

Rysunek 13. Nie określaj źródła parametrów dla parametru categoryID (kliknij, aby wyświetlić obraz pełnowymiarowy)

Po ukończeniu pracy Kreatora konfigurowania źródła danych program Visual Studio automatycznie generuje listę danych .ItemTemplate Zastąp tę wartość domyślną ItemTemplate szablonem użytym w poprzednim samouczku, a także ustaw właściwość DataList RepeatColumns na 2. Po wprowadzeniu tych zmian znaczniki deklaratywne dla listy danych i skojarzonej z nią wartości ObjectDataSource powinny wyglądać następująco:

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

CategoryProductsDataSource Obecnie parametr s ObjectDataSource categoryID nigdy nie jest ustawiony, więc żadne produkty nie są wyświetlane podczas wyświetlania strony. To, co musimy zrobić, to ustawić tę wartość parametru na CategoryID podstawie kategorii klikniętej w repeater. Wprowadza to dwa wyzwania: po pierwsze, jak określić, kiedy element LinkButton w elemencie Repeater ItemTemplate został kliknięty, a po drugie, jak możemy określić CategoryID odpowiednią kategorię, której element LinkButton został kliknięty?

Kontrolki LinkButton, takie jak Przycisk i ImageButton, mają Click zdarzenie i Command zdarzenie. Zdarzenie Click zostało zaprojektowane tak, aby po prostu pamiętać, że element LinkButton został kliknięty. Czasami jednak oprócz zauważenia, że element LinkButton został kliknięto, musimy również przekazać dodatkowe informacje do programu obsługi zdarzeń. Jeśli tak jest, właściwości i CommandArgument LinkButton CommandName można przypisać te dodatkowe informacje. Następnie po kliknięciu przycisku LinkButton jego Command zdarzenie zostanie wyzwolone (zamiast zdarzenia Click ), a program obsługi zdarzeń zostanie przekazany wartości CommandName właściwości i CommandArgument .

Gdy Command zdarzenie jest wywoływane z poziomu szablonu w repeaterze, zdarzenie repeatera ItemCommand jest wyzwalane CommandName i przekazuje wartości i CommandArgument kliknięty LinkButton (lub Przycisk lub ImageButton). W związku z tym, aby określić, kiedy kliknięto kategorię LinkButton w repeater, musimy wykonać następujące czynności:

  1. CommandName Ustaw właściwość LinkButton w repeater s ItemTemplate na wartość (użyto elementu ListProducts ). Ustawiając tę CommandName wartość, zdarzenie LinkButton jest uruchamiane po kliknięciu przycisku LinkButton Command .
  2. Ustaw właściwość LinkButton CommandArgument na wartość bieżącego elementu s CategoryID.
  3. Utwórz procedurę obsługi zdarzeń dla zdarzenia repeatera ItemCommand . W procedurze obsługi zdarzeń ustaw CategoryProductsDataSource parametr ObjectDataSource CategoryID na wartość przekazanego elementu CommandArgument.

ItemTemplate Poniższy znacznik dla repeatera kategorii implementuje kroki 1 i 2. Zwróć uwagę, CommandArgument jak wartość jest przypisywana elementowi CategoryID danych przy użyciu składni powiązania danych:

<ItemTemplate>
    <li>
        <asp:LinkButton CommandName="ListProducts"  runat="server"
            CommandArgument='<%# Eval("CategoryID") %>' ID="ViewCategory"
            Text='<%# string.Format("{0} ({1:N0})", _
                Eval("CategoryName"), Eval("NumberOfProducts")) %>'>
        </asp:LinkButton>
    </li>
</ItemTemplate>

Za każdym razem, gdy tworzysz procedurę obsługi zdarzeń, należy zawsze najpierw sprawdzić wartość przychodzącą ItemCommandCommandName, ponieważ każde zdarzenie zgłoszone przez dowolnyCommand przycisk, LinkButton lub ImageButton w repeaterze spowoduje ItemCommand wyzwolenie zdarzenia. Chociaż obecnie mamy tylko jeden taki linkButton teraz, w przyszłości (lub inny deweloper w naszym zespole) może dodać dodatkowe kontrolki sieci Web przycisku do repeater, który po kliknięciu zgłasza tę samą ItemCommand procedurę obsługi zdarzeń. Dlatego najlepiej zawsze sprawdzić CommandName właściwość i kontynuować logikę programową tylko wtedy, gdy jest zgodna z oczekiwaną wartością.

Po upewnieniu się, że przekazana CommandName wartość jest równa ListProducts, procedura obsługi zdarzeń przypisuje CategoryProductsDataSource parametr ObjectDataSource CategoryID do wartości przekazanego elementu CommandArgument. Ta modyfikacja obiektu ObjectDataSource SelectParameters powoduje automatyczne powiązanie listy danych z samym źródłem danych, co powoduje, że produkty dla nowo wybranej kategorii zostaną ponownie powiązane.

protected void Categories_ItemCommand(object source, RepeaterCommandEventArgs e)
{
    // If it's the "ListProducts" command that has been issued...
    if (string.Compare(e.CommandName, "ListProducts", true) == 0)
    {
        // Set the CategoryProductsDataSource ObjectDataSource's CategoryID parameter
        // to the CategoryID of the category that was just clicked (e.CommandArgument)...
        CategoryProductsDataSource.SelectParameters["CategoryID"].DefaultValue =
            e.CommandArgument.ToString();
    }
}

Po wykonaniu tych dodatków nasz samouczek został ukończony! Poświęć chwilę, aby przetestować go w przeglądarce. Rysunek 14 przedstawia ekran podczas pierwszej wizyty na stronie. Ponieważ kategoria nie została jeszcze wybrana, nie są wyświetlane żadne produkty. Kliknięcie kategorii, takiej jak Produkcja, powoduje wyświetlenie tych produktów w kategorii Produkt w widoku dwukolumna (zobacz Rysunek 15).

Podczas pierwszej wizyty na stronie nie są wyświetlane żadne produkty

Rysunek 14. Podczas pierwszej wizyty na stronie nie są wyświetlane żadne produkty (kliknij, aby wyświetlić obraz pełnowymiarowy)

Kliknięcie pozycji Produkcja kategorii Listy pasujących produktów po prawej stronie

Rysunek 15. Kliknięcie pozycji Produkcja kategorii Listy pasujących produktów po prawej stronie (kliknij, aby wyświetlić obraz pełnowymiarowy)

Podsumowanie

Jak pokazano w tym samouczku i poprzednim, raporty wzorca/szczegółów można rozłożyć na dwie strony lub skonsolidować na jednej. Wyświetlenie raportu wzorca/szczegółów na jednej stronie powoduje jednak pewne wyzwania związane z układem rekordów wzorcowych i szczegółów na stronie. W elemecie Master/Detail Using a Selectable Master GridView with a DetailsView (Szczegóły) mieliśmy rekordy szczegółów wyświetlane powyżej rekordów głównych; W tym samouczku użyliśmy technik CSS, aby rekordy główne były zmiennoprzecinkowe po lewej stronie szczegółów.

Oprócz wyświetlania raportów wzorca/szczegółów mieliśmy również okazję dowiedzieć się, jak pobrać liczbę produktów skojarzonych z każdą kategorią, a także jak wykonać logikę po stronie serwera, gdy element LinkButton (lub Przycisk lub ImageButton) jest klikany z poziomu repeatera.

Ten samouczek kończy badanie raportów master/detail za pomocą elementów DataList i Repeater. W następnym zestawie samouczków pokazano, jak dodać możliwości edytowania i usuwania do kontrolki DataList.

Szczęśliwe programowanie!

Dalsze informacje

Aby uzyskać więcej informacji na temat tematów omówionych w tym samouczku, zapoznaj się z następującymi zasobami:

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łównym recenzentem tego samouczka był Zack Jones. Chcesz przejrzeć nadchodzące artykuły MSDN? Jeśli tak, upuść mi wiersz pod adresemmitchell@4GuysFromRolla.com .