Sdílet prostřednictvím


Vytvoření vlastního uživatelského rozhraní pro řazení (VB)

Scott Mitchell

Stáhnout PDF

Při zobrazení dlouhého seznamu seřazených dat může být velmi užitečné seskupit související data zavedením oddělovače řádků. V tomto kurzu se dozvíte, jak vytvořit takové uživatelské rozhraní pro řazení.

Úvod

Při zobrazení dlouhého seznamu seřazených dat, kde je v seřazených sloupcích jen několik různých hodnot, může být pro koncového uživatele obtížné rozpoznat, kde přesně dochází k rozdílům. V databázi je například 81 produktů, ale pouze devět různých kategorií (osm jedinečných kategorií plus NULL možnost). Vezměte v úvahu případ uživatele, který má zájem o zkoumání produktů, které spadají do kategorie Mořské plody. Na stránce, která obsahuje seznam všech produktů v jednom GridView, se uživatel může rozhodnout, že nejlepší tip je seřadit výsledky podle kategorie, která seskupí všechny produkty z mořských plodů dohromady. Po seřazení podle kategorie musí uživatel projít seznam a hledat, kde začínají a končí produkty seskupené z mořských plodů. Vzhledem k tomu, že výsledky jsou seřazeny abecedně podle názvu kategorie, není nalezení produktů z mořských plodů obtížné, ale stále vyžaduje důkladnou kontrolu seznamu položek v mřížce.

Aby bylo možné zvýraznit hranice mezi seřazenými skupinami, mnoho webů používá uživatelské rozhraní, které mezi tyto skupiny přidává oddělovač. Oddělovače, jako jsou ty zobrazené na obrázku 1, umožňují uživateli rychleji najít konkrétní skupinu a identifikovat její hranice a také zjistit, jaké jedinečné skupiny v datech existují.

Každá skupina kategorií je jasně identifikována.

Obrázek 1: Každá skupina kategorií je jasně identifikována (kliknutím zobrazíte obrázek v plné velikosti)

V tomto kurzu se dozvíte, jak vytvořit takové uživatelské rozhraní pro řazení.

Krok 1: Vytvoření standardního seřaditelného objektu GridView

Než prozkoumáme, jak rozšířit GridView o vylepšené rozhraní pro řazení, pojďme nejprve vytvořit standardní, řaditelný GridView, který obsahuje seznam produktů. Začněte otevřením CustomSortingUI.aspx stránky ve PagingAndSorting složce. Přidejte objekt GridView na stránku, nastavte jeho ID vlastnost na ProductLista vytvořte vazbu s novým objektem ObjectDataSource. Nakonfigurujte ObjectDataSource tak, aby pro výběr záznamů používal metodu ProductsBLL třídy s GetProducts() .

Dále nakonfigurujte Objekt GridView tak, aby obsahoval ProductNamepouze , CategoryNameSupplierName, a UnitPrice BoundFields a Ukončené pole CheckBoxField. Nakonec nakonfigurujte GridView tak, aby podporoval řazení zaškrtnutím políčka Povolit řazení v inteligentní značce GridView (nebo nastavením jeho AllowSorting vlastnosti na true). Po provedení těchto přidání na CustomSortingUI.aspx stránku by deklarativní kód měl vypadat nějak takto:

<asp:GridView ID="ProductList" runat="server" AllowSorting="True"
    AutoGenerateColumns="False" DataKeyNames="ProductID"
    DataSourceID="ObjectDataSource1" EnableViewState="False">
    <Columns>
        <asp:BoundField DataField="ProductName" HeaderText="Product"
            SortExpression="ProductName" />
        <asp:BoundField DataField="CategoryName" HeaderText="Category"
            ReadOnly="True" SortExpression="CategoryName" />
        <asp:BoundField DataField="SupplierName" HeaderText="Supplier"
            ReadOnly="True" SortExpression="SupplierName" />
        <asp:BoundField DataField="UnitPrice" DataFormatString="{0:C}"
            HeaderText="Price" HtmlEncode="False" SortExpression="UnitPrice" />
        <asp:CheckBoxField DataField="Discontinued" HeaderText="Discontinued"
            SortExpression="Discontinued" />
    </Columns>
</asp:GridView>
<asp:ObjectDataSource ID="ObjectDataSource1" runat="server"
    OldValuesParameterFormatString="original_{0}" SelectMethod="GetProducts"
    TypeName="ProductsBLL"></asp:ObjectDataSource>

Podívejte se na náš dosavadní pokrok v prohlížeči. Obrázek 2 znázorňuje řaditelný objekt GridView, když jsou jeho data seřazena podle kategorií v abecedním pořadí.

Data řaditelného objektu GridView s jsou seřazená podle kategorie.

Obrázek 2: Data typu GridView s řazením jsou seřazená podle kategorie (kliknutím zobrazíte obrázek v plné velikosti)

Krok 2: Prozkoumání technik pro přidání řádků oddělovače

Po dokončení obecného objektu GridView, který lze seřadit, zbývá jen přidat řádky oddělovače v GridView před každou jedinečnou seřazenou skupinu. Ale jak mohou být takové řádky vloženy do GridView? V podstatě potřebujeme iterovat řádky GridView s, určit, kde dochází k rozdílům mezi hodnotami v seřazených sloupcích, a pak přidat příslušný řádek oddělovače. Při úvahách o tomto problému se zdá přirozené, že řešení leží někde v obslužné rutině události GridView s RowDataBound . Jak jsme probrali v kurzu Vlastní formátování založené na datech , tato obslužná rutina události se běžně používá při použití formátování na úrovni řádků na základě dat řádků. Obslužná rutina RowDataBound události zde však není řešením, protože řádky nelze přidat do objektu GridView programově z této obslužné rutiny události. Kolekce GridView s Rows je ve skutečnosti jen pro čtení.

Pokud chcete do objektu GridView přidat další řádky, máme tři možnosti:

  • Přidejte tyto řádky oddělovače metadat ke skutečným datům, která jsou svázaná s objektem GridView.
  • Po vazbě objektu GridView na data přidejte do kolekce ovládacích prvků GridView s další TableRow instance.
  • Vytvoření vlastního serverového ovládacího prvku, který rozšiřuje ovládací prvek GridView a přepíše metody zodpovědné za vytvoření struktury GridView s

Vytvoření vlastního serverového ovládacího prvku by bylo nejlepší, pokud by tato funkce byla potřebná na mnoha webových stránkách nebo na několika webech. To by však vyžadovalo poměrně málo kódu a důkladné prozkoumání do hloubky vnitřních fungování GridView. Proto tuto možnost v tomto kurzu nebudeme brát v úvahu.

Další dvě možnosti přidání oddělovacích řádků do skutečných dat vázaných na GridView a manipulace s gridView s kolekce ovládacích prvků po jeho vazbě - útok na problém odlišně a zaslouží si diskuzi.

Přidání řádků k datům vázaným na GridView

Když je Objekt GridView vázán na zdroj dat, vytvoří GridViewRow pro každý záznam vrácený zdrojem dat. Proto můžeme vložit potřebné oddělovací řádky přidáním záznamů oddělovače do zdroje dat před jeho vazbou na GridView. Tento koncept znázorňuje obrázek 3.

Jedna technika zahrnuje přidání řádků oddělovače do zdroje dat

Obrázek 3: Jedna technika zahrnuje přidání oddělovačů řádků do zdroje dat

Používám termín oddělovač záznamů v uvozovkách, protože neexistuje žádný zvláštní oddělovač záznamu; místo toho musíme nějak označit příznakem, že konkrétní záznam ve zdroji dat slouží jako oddělovač, nikoli jako normální řádek dat. V našich příkladech svážeme instanci s objektem ProductsDataTable GridView, který se skládá z objektu ProductRows. Záznam můžeme označit jako řádek oddělovače nastavením jeho CategoryID vlastnosti na -1 (protože taková hodnota nemohla normálně existovat).

Abychom mohli tuto techniku využít, museli bychom provést následující kroky:

  1. Programové načtení dat pro vazbu na GridView ( ProductsDataTable instance)
  2. Řazení dat na základě vlastností GridView SortExpressionSortDirection
  3. Iterujte v ProductsDataTablesouboru a vyhledejteProductsRows, kde leží rozdíly v seřazených sloupcích.
  4. Na hranici každé skupiny vložte instanci oddělovače záznamu ProductsRow do tabulky DataTable, která je nastavená CategoryID na -1 (nebo jakékoli označení bylo rozhodnuto označit záznam jako oddělovač záznamu).
  5. Po vložení oddělovačů řádky, programově svázat data s GridView

Kromě těchto pěti kroků bychom také potřebovali poskytnout obslužnou rutinu události pro událost GridView s RowDataBound . Tady každý z nich DataRow zkontrolujeme a určíme, jestli se jedná o řádek oddělovače, jehož CategoryID nastavení bylo -1. Pokud ano, pravděpodobně bychom chtěli upravit jeho formátování nebo text zobrazený v buňkách.

Použití této techniky pro vložení hranic skupin řazení vyžaduje trochu více práce, než je uvedeno výše, protože potřebujete také poskytnout obslužnou rutinu události pro událost GridView s Sorting a sledovat SortExpression hodnoty a SortDirection .

Manipulace se kolekcí ovládacích prvků GridView s po příchozím datu

Místo zasílání zpráv o datech před jejich vazbou na GridView, můžeme přidat řádky oddělovače poté , co byla data svázána s GridView. Proces datové vazby vytváří hierarchii ovládacích prvků GridView s, což je ve skutečnosti jednoduše Table instance složená z kolekce řádků, z nichž každý se skládá z kolekce buněk. Konkrétně kolekce ovládacích prvků GridView s obsahuje Table objekt v kořenovém adresáři, GridViewRow objekt (který je odvozen z TableRow třídy) pro každý záznam ve DataSource vazbě na GridView a TableCell objekt v každé GridViewRow instanci pro každé datové pole v objektu DataSource.

Pokud chcete přidat oddělovací řádky mezi každou skupinu řazení, můžeme s touto hierarchií ovládacích prvků po jejím vytvoření přímo manipulovat. Můžeme si být jistí, že hierarchie ovládacích prvků GridView s byla naposledy vytvořena v době vykreslení stránky. Proto tento přístup přepíše metodu Page třídy s Render , v tomto okamžiku se aktualizuje hierarchie ovládacích prvků GridView s tak, aby zahrnovala potřebné oddělovací řádky. Tento proces znázorňuje obrázek 4.

Alternativní technika manipuluje s hierarchií ovládacích prvků GridView s

Obrázek 4: Alternativní technika manipuluje s hierarchií ovládacích prvků GridView (kliknutím zobrazíte obrázek v plné velikosti)

V tomto kurzu použijeme tento druhý přístup k přizpůsobení uživatelského prostředí řazení.

Poznámka

Kód, který prezentuji v tomto kurzu, je založený na příkladu uvedeném v položce blogu Teemu Keiski s Hrou bitů se seskupováním řazení GridView.

Krok 3: Přidání oddělovače řádků do hierarchie ovládacích prvků GridView s

Vzhledem k tomu, že chceme přidat oddělovací řádky do hierarchie ovládacích prvků GridView s až po vytvoření a vytvoření hierarchie ovládacích prvků při poslední návštěvě této stránky, chceme toto přidání provést na konci životního cyklu stránky, ale před vykreslení skutečné hierarchie ovládacích prvků GridView do HTML. Poslední možný bod, ve kterém toho můžeme dosáhnout, je Page událost třídy s Render , kterou můžeme přepsat v naší třídě kódu na pozadí pomocí následujícího podpisu metody:

Protected Overrides Sub Render(ByVal writer As HtmlTextWriter)
   ' Add code to manipulate the GridView control hierarchy
   MyBase.Render(writer)
End Sub

Při vyvolání Pagebase.Render(writer) původní Render metody třídy s se vykreslí každý ovládací prvek na stránce a vygeneruje značky na základě jejich hierarchie ovládacích prvků. Proto je nutné, abychom oba volali base.Render(writer), aby stránka byla vykreslena a abychom před voláním base.Render(writer)manipulovali s hierarchií ovládacích prvků GridView s tak, aby oddělovací řádky byly přidány do hierarchie ovládacích prvků GridView s před jeho vykreslení.

Pokud chcete vložit hlavičky skupiny řazení, musíme nejprve zajistit, aby uživatel požádal o seřazení dat. Ve výchozím nastavení není obsah GridView s seřazen, a proto nemusíme zadávat záhlaví řazení skupin.

Poznámka

Pokud chcete, aby byl GridView při prvním načtení stránky seřazen podle konkrétního sloupce, zavolejte metodu GridView s Sort při první návštěvě stránky (ale ne při následných postbackech). Chcete-li toho dosáhnout, přidejte toto volání do obslužné rutiny Page_Load události v rámci podmíněného if (!Page.IsPostBack) . Další Sort informace o metodě najdete v kurzu Stránkování a řazení dat sestavy.

Za předpokladu, že jsou data seřazená, je naším dalším úkolem určit, podle kterého sloupce byla data seřazena, a pak prohledávat řádky a hledat rozdíly v hodnotách daného sloupce. Následující kód zajistí, že jsou data seřazená, a najde sloupec, podle kterého byla data seřazena:

Protected Overrides Sub Render(ByVal writer As HtmlTextWriter)
    ' Only add the sorting UI if the GridView is sorted
    If Not String.IsNullOrEmpty(ProductList.SortExpression) Then
        ' Determine the index and HeaderText of the column that
        'the data is sorted by
        Dim sortColumnIndex As Integer = -1
        Dim sortColumnHeaderText As String = String.Empty
        For i As Integer = 0 To ProductList.Columns.Count - 1
            If ProductList.Columns(i).SortExpression.CompareTo( _
                ProductList.SortExpression) = 0 Then
                sortColumnIndex = i
                sortColumnHeaderText = ProductList.Columns(i).HeaderText
                Exit For
            End If
        Next
        ' TODO: Scan the rows for differences in the sorted column�s values
End Sub

Pokud GridView ještě není seřazen, GridView s SortExpression vlastnost nebyla nastavena. Proto chceme přidat řádky oddělovače pouze v případě, že tato vlastnost má nějakou hodnotu. Pokud ano, musíme dále určit index sloupce, podle kterého byla data seřazena. Toho lze dosáhnout tak, že procházíme kolekci GridView s Columns a vyhledáte sloupec, jehož SortExpression vlastnost se rovná vlastnosti GridView s SortExpression . Kromě indexu sloupce uchopíme HeaderText také vlastnost, která se používá při zobrazení řádků oddělovače.

S indexem sloupce, podle kterého jsou data seřazena, je posledním krokem výčet řádků GridView. U každého řádku musíme určit, jestli se hodnota seřazeného sloupce liší od hodnoty seřazeného sloupce předchozího řádku. Pokud ano, musíme do hierarchie řízení vložit novou GridViewRow instanci. K tomu slouží následující kód:

Protected Overrides Sub Render(ByVal writer As HtmlTextWriter)
    ' Only add the sorting UI if the GridView is sorted
    If Not String.IsNullOrEmpty(ProductList.SortExpression) Then
        ' ... Code for finding the sorted column index removed for brevity ...
        ' Reference the Table the GridView has been rendered into
        Dim gridTable As Table = CType(ProductList.Controls(0), Table)
        ' Enumerate each TableRow, adding a sorting UI header if
        ' the sorted value has changed
        Dim lastValue As String = String.Empty
        For Each gvr As GridViewRow In ProductList.Rows
            Dim currentValue As String = gvr.Cells(sortColumnIndex).Text
            If lastValue.CompareTo(currentValue) <> 0 Then
                ' there's been a change in value in the sorted column
                Dim rowIndex As Integer = gridTable.Rows.GetRowIndex(gvr)
                ' Add a new sort header row
                Dim sortRow As New GridViewRow(rowIndex, rowIndex, _
                    DataControlRowType.DataRow, DataControlRowState.Normal)
                Dim sortCell As New TableCell()
                sortCell.ColumnSpan = ProductList.Columns.Count
                sortCell.Text = String.Format("{0}: {1}", _
                    sortColumnHeaderText, currentValue)
                sortCell.CssClass = "SortHeaderRowStyle"
                ' Add sortCell to sortRow, and sortRow to gridTable
                sortRow.Cells.Add(sortCell)
                gridTable.Controls.AddAt(rowIndex, sortRow)
                ' Update lastValue
                lastValue = currentValue
            End If
        Next
    End If
    MyBase.Render(writer)
End Sub

Tento kód začíná tím, že programově odkazuje Table na objekt nalezený v kořenovém adresáři hierarchie ovládacího prvku GridView s a vytvoří řetězcovou proměnnou s názvem lastValue. lastValue slouží k porovnání hodnoty aktuálního řádku seřazeného sloupce s hodnotou s předchozím řádkem. Dále je výčtem kolekce GridView s Rows a pro každý řádek je hodnota seřazeného sloupce uložena currentValue v proměnné.

Poznámka

K určení hodnoty konkrétního sloupce s seřazeného řádku používám vlastnost buňky s Text . To funguje dobře pro BoundFields, ale nebude fungovat podle požadavků pro TemplateFields, CheckBoxFields atd. Za chvíli se podíváme na to, jak zohlednit alternativní pole GridView.

Proměnné currentValue a lastValue se pak porovnávají. Pokud se liší, musíme do hierarchie ovládacích prvků přidat nový řádek oddělovače. Toho dosáhnete určením indexu objektu GridViewRow v Table kolekci objektů Rows , vytvořením nových GridViewRow instancí a TableCell následným přidáním TableCell a GridViewRow do hierarchie ovládacích prvků.

Všimněte si, že oddělovač řádků s lone TableCell je formátován tak, aby přesahoval celou šířku GridView, je formátován pomocí SortHeaderRowStyle třídy CSS a má svou Text vlastnost tak, že zobrazuje název skupiny řazení (například Category ) a hodnotu skupiny (například Nápoje ). lastValue Nakonec se aktualizuje na hodnotu currentValue.

V souboru musí být zadána Styles.css třída CSS použitá k formátování řádku SortHeaderRowStyle záhlaví skupiny řazení. Nebojte se použít jakékoli nastavení stylu, které vás osloví; Použil(a) jsem následující:

.SortHeaderRowStyle
{
    background-color: #c00;
    text-align: left;
    font-weight: bold;
    color: White;
}

S aktuálním kódem přidává rozhraní pro řazení hlavičky skupin řazení při řazení podle libovolného BoundField (viz Obrázek 5, který ukazuje snímek obrazovky při řazení podle dodavatele). Při řazení podle jiného typu pole (například CheckBoxField nebo TemplateField) se ale záhlaví skupin řazení nikde nenajdou (viz Obrázek 6).

Rozhraní pro řazení zahrnuje záhlaví skupin řazení při řazení podle BoundFields

Obrázek 5: Rozhraní pro řazení zahrnuje při řazení podle BoundFields záhlaví skupin (kliknutím zobrazíte obrázek v plné velikosti)

Při řazení pole CheckBoxField chybí záhlaví skupiny řazení.

Obrázek 6: Při řazení pole CheckBoxField chybí záhlaví skupiny řazení (kliknutím zobrazíte obrázek v plné velikosti)

Důvod, proč při řazení podle CheckBoxField chybí hlavičky skupin řazení, je to, že kód v současné době používá pouze TableCell vlastnost s Text k určení hodnoty seřazeného sloupce pro každý řádek. U CheckBoxFields TableCell je vlastnost s Text prázdný řetězec; místo toho je hodnota k dispozici prostřednictvím webového ovládacího prvku CheckBox, který se nachází v kolekci TableCell s Controls .

Abychom mohli zpracovávat jiné typy polí než BoundFields, musíme rozšířit kód, ve kterém currentValue je proměnná přiřazená, abychom zkontrolovali existenci CheckBoxu v kolekci TableCell s Controls . Místo použití currentValue = gvr.Cells(sortColumnIndex).Textnahraďte tento kód následujícím kódem:

Dim currentValue As String = String.Empty
If gvr.Cells(sortColumnIndex).Controls.Count > 0 Then
    If TypeOf gvr.Cells(sortColumnIndex).Controls(0) Is CheckBox Then
        If CType(gvr.Cells(sortColumnIndex).Controls(0), CheckBox).Checked Then
            currentValue = "Yes"
        Else
            currentValue = "No"
        End If
        ' ... Add other checks here if using columns with other
        '      Web controls in them (Calendars, DropDownLists, etc.) ...
    End If
Else
    currentValue = gvr.Cells(sortColumnIndex).Text
End If

Tento kód prozkoumá seřazený sloupec TableCell pro aktuální řádek a určí, jestli v kolekci Controls existují nějaké ovládací prvky. Pokud existuje a první ovládací prvek je CheckBox, currentValue proměnná je nastavena na Ano nebo Ne v závislosti na vlastnosti CheckBox s Checked . V opačném případě je hodnota převzata TableCell z vlastnosti s Text . Tuto logiku lze replikovat pro zpracování řazení pro všechna pole template, která mohou existovat v GridView.

S výše uvedeným přidáním kódu jsou teď při řazení podle pole Ukončeno CheckBoxField k dispozici záhlaví skupin řazení (viz Obrázek 7).

Při řazení polí CheckBoxField jsou nyní k dispozici záhlaví skupin řazení.

Obrázek 7: Při řazení polí CheckBoxField jsou teď k dispozici záhlaví skupin řazení (kliknutím zobrazíte obrázek v plné velikosti)

Poznámka

Pokud máte produkty s databázovými NULL hodnotami pro CategoryIDpole , SupplierID, nebo UnitPrice , budou se tyto hodnoty ve výchozím nastavení zobrazovat jako prázdné řetězce v GridView, což znamená, že text oddělovače řádků pro tyto produkty s NULL hodnotami bude vypadat jako Kategorie: (to znamená, že neexistuje žádný název za Kategorie: jako u Kategorie: Nápoje ). Pokud chcete zobrazit hodnotu zde můžete nastavit BoundFields NullDisplayText vlastnost na text, který chcete zobrazit, nebo můžete přidat podmíněný příkaz v Render metoda při přiřazení currentValue vlastnosti oddělovače řádku s Text .

Souhrn

GridView neobsahuje mnoho předdefinovaných možností pro přizpůsobení rozhraní pro řazení. S trochou kódu nízké úrovně je však možné upravit hierarchii ovládacích prvků GridView s a vytvořit více přizpůsobené rozhraní. V tomto kurzu jsme viděli, jak přidat řádek oddělovače skupin řazení pro řaditelné zobrazení GridView, který snadněji identifikuje jedinečné skupiny a hranice těchto skupin. Další příklady přizpůsobených rozhraní pro řazení najdete na blogu Scott Guthrie s A Few ASP.NET 2.0 GridView Sorting Tips and Tricks .

Šťastné programování!

O autorovi

Scott Mitchell, autor sedmi knih o ASP/ASP.NET a zakladatel 4GuysFromRolla.com, pracuje s webovými technologiemi Microsoftu od roku 1998. Scott pracuje jako nezávislý konzultant, školitel a spisovatel. Jeho nejnovější kniha je Sams Teach Yourself ASP.NET 2.0 in 24 Hours. Můžete ho najít na mitchell@4GuysFromRolla.comadrese . nebo prostřednictvím jeho blogu, který najdete na http://ScottOnWriting.NETadrese .