Megjegyzés
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhat bejelentkezni vagy módosítani a címtárat.
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhatja módosítani a címtárat.
által Scott Mitchell
A rendezett adatok hosszú listájának megjelenítésekor nagyon hasznos lehet a kapcsolódó adatok csoportosítása elválasztó sorok bevezetésével. Ebben az oktatóanyagban meglátjuk, hogyan hozhatunk létre ilyen rendezési felhasználói felületet.
Bevezetés
Ha rendezett adatok hosszú listáját jeleníti meg, ahol csak néhány különböző érték van a rendezett oszlopban, a végfelhasználó nehezen tudja megállapítani, hogy pontosan hol fordulnak elő a különbséghatárok. Például 81 termék van az adatbázisban, de csak kilenc különböző kategória (nyolc egyedi kategória plusz az NULL opció). Vegyük egy olyan felhasználó esetét, aki érdeklődik a tenger gyümölcsei kategóriába tartozó termékek vizsgálata iránt. Egy olyan oldalon, amely az összes terméket egyetlen GridView-ban sorolja fel, a felhasználó úgy dönthet, hogy a legjobb megoldás az, ha kategóriák szerint rendezi az eredményeket, amelyek az összes tenger gyümölcseit csoportosítják. A kategória szerinti rendezés után a felhasználónak át kell kutatnia a listát, és meg kell keresnie, hogy a tenger gyümölcsei által csoportosított termékek hol kezdődnek és végződnek. Mivel az eredmények a kategória neve szerint ábécé sorrendben vannak rendezve, a tenger gyümölcsei termékek megtalálása nem nehéz, de még mindig alaposan át kell vizsgálni a rácsban lévő elemek listáját.
A rendezett csoportok közötti határok kiemelése érdekében sok webhely olyan felhasználói felületet használ, amely elválasztót ad az ilyen csoportok között. Az 1. ábrán láthatókhoz hasonló elválasztók lehetővé teszik a felhasználó számára, hogy gyorsabban megtaláljon egy adott csoportot és azonosítsa annak határait, valamint megbizonyosodjon arról, hogy milyen különálló csoportok léteznek az adatokban.
1. ábra: Minden kategóriacsoport egyértelműen azonosítva van (kattintson a teljes méretű kép megtekintéséhez)
Ebben az oktatóanyagban meglátjuk, hogyan hozhatunk létre ilyen rendezési felhasználói felületet.
1. lépés: Szabványos, rendezhető rácsnézet létrehozása
Mielőtt megvizsgálnánk, hogyan bővíthetjük a GridView-t a továbbfejlesztett rendezési felület biztosításához, először hozzon létre egy szabványos, rendezhető GridView-t, amely felsorolja a termékeket. Először nyissa meg a CustomSortingUI.aspx lapot a PagingAndSorting mappában. Adjon hozzá egy GridView-t az oldalhoz, állítsa a ID tulajdonságát értékre ProductList, és kösse egy új ObjectDataSource-hoz. Konfigurálja az ObjectDataSource-t úgy, hogy az ProductsBLL s osztály GetProducts() metódusát használja a rekordok kiválasztásához.
Ezután konfigurálja a GridView-t úgy, hogy csak a ProductName, CategoryName, SupplierNameés a UnitPrice BoundFields, valamint a megszűnt CheckBoxField értéket tartalmazza. Végül állítsa be a GridView-t a rendezés támogatására a GridView intelligens címkéjében található Rendezés engedélyezése jelölőnégyzet bejelölésével (vagy a AllowSorting tulajdonságának beállításával true). Miután elvégezte ezeket a kiegészítéseket az CustomSortingUI.aspx oldalon, a deklaratív jelölésnek az alábbihoz hasonlóan kell kinéznie:
<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>
Szánjon egy percet arra, hogy megtekintse eddigi előrehaladásunkat egy böngészőben. A 2. ábra a rendezhető GridView-t mutatja, ha adatai kategóriák szerint vannak ábécé sorrendben rendezve.
2. ábra: A rendezhető GridView adatai kategória szerint vannak rendezve (kattintson a teljes méretű kép megtekintéséhez)
2. lépés: Az elválasztó sorok hozzáadásának technikáinak feltárása
Az általános, rendezhető GridView elkészültével már csak az marad, hogy minden egyedi rendezett csoport elé hozzá tudjuk adni az elválasztó sorokat a GridView-hoz. De hogyan lehet ilyen sorokat beszúrni a GridView-ba? Lényegében végig kell iterálnunk a GridView sorain, meg kell határoznunk, hogy hol fordulnak elő különbségek a rendezett oszlop értékei között, majd hozzá kell adnunk a megfelelő elválasztó sort. Ha erre a problémára gondolunk, természetesnek tűnik, hogy a megoldás valahol a GridView eseménykezelőjében RowDataBound rejlik. Amint azt az Adatok alapján egyéni formázás oktatóanyagban tárgyaltuk, ezt az eseménykezelőt gyakran használják a sor adatai alapján sorszintű formázás alkalmazásakor. Az eseménykezelő azonban RowDataBound itt nem a megoldás, mivel ebből az eseménykezelőből nem lehet programozott módon sorokat hozzáadni a GridView-hoz. A GridView gyűjteménye Rows valójában csak olvasható.
További sorok hozzáadásához a GridView-hoz három lehetőség közül választhatunk:
- Adja hozzá ezeket a metaadat-elválasztó sorokat a GridView-hoz kötött tényleges adatokhoz
- Miután a GridView az adatokhoz van kötve, adjon hozzá további
TableRowpéldányokat a GridView vezérlőgyűjteményéhez - Hozzon létre egy egyéni kiszolgálóvezérlőt, amely kiterjeszti a GridView vezérlőt, és felülbírálja a GridView struktúrájának felépítéséért felelős metódusokat
Egyéni kiszolgálóvezérlő létrehozása lenne a legjobb megoldás, ha erre a funkcióra sok weblapon vagy több webhelyen lenne szükség. Ez azonban elég sok kódot és a GridView belső működésének mélyreható feltárását igényelné. Ezért nem vesszük figyelembe ezt a lehetőséget ebben az oktatóanyagban.
A másik két lehetőség, az elválasztó sorok hozzáadása a GridView-hoz kötött tényleges adatokhoz, és a GridView vezérlőgyűjteményének manipulálása a kötés után - másképp támadja meg a problémát, és megérdemel egy megbeszélést.
Sorok hozzáadása a GridView-hoz kötött adatokhoz
Ha a GridView egy adatforráshoz van kötve, létrehoz egy GridViewRow adatforrás által visszaadott minden rekordhoz. Ezért beszúrhatjuk a szükséges elválasztó sorokat úgy, hogy elválasztó rekordokat adunk hozzá az adatforráshoz, mielőtt a GridView-hoz kötnénk. A 3. ábra szemlélteti ezt a koncepciót.
3. ábra: Az egyik technika az elválasztó sorok hozzáadása az adatforráshoz
Az elválasztó rekordok kifejezést idézőjelben használom, mert nincs speciális elválasztó rekord; Ehelyett valahogy meg kell jelölnünk, hogy az adatforrás egy adott rekordja elválasztóként szolgál, nem pedig normál adatsorként. Példáinkban egy ProductsDataTable példányt újra a GridView-hoz kötünk, amely a következőkből ProductRowsáll: . Megjelölhetünk egy rekordot elválasztó sorként, ha a tulajdonságát CategoryID-1 (mivel egy ilyen érték normálisan nem létezhet).
Ennek a technikának a használatához a következő lépéseket kell végrehajtanunk:
- A GridView-hoz (egy
ProductsDataTablepéldányhoz) való kötéshez szükséges adatok programozott módon történő lekérése - Az adatok rendezése a GridView s
SortExpressionésSortDirectiontulajdonságok alapján - Iterálja a
ProductsRowsProductsDataTable, és keresse meg, hol vannak a különbségek a rendezett oszlopban - Minden csoporthatáron injektáljon be egy elválasztó rekordpéldányt
ProductsRowa DataTable-be, amelybe be vanCategoryIDállítva-1(vagy bármilyen megjelölést választottak, hogy egy rekordot elválasztó rekordként jelöljenek meg) - Az elválasztó sorok beszúrása után programozott módon kösse az adatokat a GridView-hoz
Ezen az öt lépésen kívül egy eseménykezelőt is meg kell adnunk a GridView s RowDataBound eseményhez. Itt mindegyiket DataRow ellenőrizzük, és megállapítjuk, hogy elválasztó sorról van-e szó, amelynek CategoryID beállítása .-1 Ha igen, akkor valószínűleg módosítani akarjuk a formázását vagy a cellákban megjelenő szöveget.
Ennek a technikának a használata a rendezési csoport határainak beszúrásához a fent ismertetettnél valamivel több munkát igényel, mivel egy eseménykezelőt is meg kell adnia a GridView s Sorting eseményhez, és nyomon kell követnie az SortExpression és értékeket SortDirection .
A GridView s vezérlőgyűjteményének kezelése az adatkötés után
Ahelyett, hogy üzenetet küldenénk az adatoknak, mielőtt a GridView-hoz kötnénk, hozzáadhatjuk az elválasztó sorokat, miután az adatokat a GridView-hoz kötötték. Az adatkötés folyamata felépíti a GridView vezérlési hierarchiáját, amely a valóságban egyszerűen egy Table példány, amely sorok gyűjteményéből áll, amelyek mindegyike cellák gyűjteményéből áll. Pontosabban, a GridView vezérlőgyűjteménye tartalmaz egy Table objektumot a gyökerében, egy GridViewRow (amely az TableRow osztályból származik) a GridView-hoz kötött minden rekordhoz DataSource , és egy objektumot TableCell minden GridViewRow példányban DataSourcea .
Az egyes rendezési csoportok közötti elválasztó sorok hozzáadásához közvetlenül módosíthatjuk ezt a vezérlőhierarchiát, miután létrehoztuk. Biztosak lehetünk abban, hogy a GridView vezérlőhierarchiája utoljára létrejött az oldal megjelenítéséig. Ezért ez a megközelítés felülbírálja az Page s osztály Render metódusát, ekkor a GridView végső vezérlőhierarchiája frissül, hogy tartalmazza a szükséges elválasztó sorokat. A 4. ábra szemlélteti ezt a folyamatot.
4. ábra: Egy alternatív technika manipulálja a GridView vezérlőhierarchiáját (kattintson a teljes méretű kép megtekintéséhez)
Ebben az oktatóanyagban ez utóbbi megközelítést fogjuk használni a rendezési felhasználói élmény testreszabásához.
Megjegyzés:
Az ebben az oktatóanyagban bemutatott kód Teemu Keiski blogbejegyzésében található példán alapul, Playing a Bit with GridView Sort Grouping.
3. lépés: Az elválasztó sorok hozzáadása a GridView vezérlőhierarchiájához
Mivel az elválasztó sorokat csak a vezérlőhierarchia létrehozása és az oldal látogatása során utoljára történő létrehozása után szeretnénk hozzáadni a GridView vezérlőhierarchiájához, ezt a kiegészítést az oldal életciklusának végén, de a tényleges GridView vezérlőhierarchia HTML-be való megjelenítése előtt szeretnénk végrehajtani. A legkésőbbi lehetséges pont, ahol ezt megvalósíthatjuk, az Page s Render osztály eseménye, amelyet a kód mögötti osztályunkban a következő metódusaláírással bírálhatunk felül:
Protected Overrides Sub Render(ByVal writer As HtmlTextWriter)
' Add code to manipulate the GridView control hierarchy
MyBase.Render(writer)
End Sub
Az Page osztály eredeti Render metódusának meghívásakor base.Render(writer) az oldalon lévő összes vezérlő megjelenik, és a jelölés a vezérlőhierarchiájuk alapján jön létre. Ezért elengedhetetlen, hogy mindketten meghívjuk base.Render(writer)a , hogy az oldal megjelenjen, és hogy a hívás base.Render(writer)előtt módosítsuk a GridView vezérlőhierarchiáját, hogy az elválasztó sorok a megjelenítés előtt hozzá legyenek adva a GridView vezérlőhierarchiájához.
A rendezési csoport fejléceinek beszúrásához először meg kell győződnünk arról, hogy a felhasználó kérte-e az adatok rendezését. Alapértelmezés szerint a GridView tartalma nincs rendezve, ezért nem kell megadnunk semmilyen csoportrendezési fejlécet.
Megjegyzés:
Ha azt szeretné, hogy a GridView egy adott oszlop szerint legyen rendezve az oldal első betöltésekor, hívja meg a GridView s Sort metódust az első oldallátogatáskor (de ne a későbbi visszaküldéseknél). Ehhez adja hozzá ezt a hívást az eseménykezelőhöz Page_Load egy if (!Page.IsPostBack) feltételen belül. A módszerrel kapcsolatos további információkért tekintse meg a Sort oktatóanyagát.
Feltételezve, hogy az adatok rendezve vannak, a következő feladatunk annak meghatározása, hogy melyik oszlop szerint rendeztük az adatokat, majd megvizsgáljuk a sorokat, és keressük az oszlop értékei közötti különbségeket. A következő kód biztosítja az adatok rendezését, és megkeresi azt az oszlopot, amely alapján az adatok rendezve vannak:
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
Ha a GridView még nem lett rendezve, akkor a GridView s tulajdonsága SortExpression nem lesz beállítva. Ezért csak akkor szeretnénk hozzáadni az elválasztó sorokat, ha ennek a tulajdonságnak van valamilyen értéke. Ha igen, akkor ezután meg kell határoznunk annak az oszlopnak az indexét, amely alapján az adatokat rendeztük. Ezt úgy érhetjük el, hogy végigfutunk a GridView gyűjteményen Columns , és megkeresjük azt az oszlopot, amelynek SortExpression tulajdonsága megegyezik a GridView s SortExpression tulajdonságával. Az s index oszlop mellett megragadjuk a tulajdonságot HeaderText is, amelyet az elválasztó sorok megjelenítésénél használunk.
Annak az oszlopnak az indexével, amely alapján az adatok rendezve vannak, az utolsó lépés a GridView sorainak számbavétele. Minden sornál meg kell határoznunk, hogy a rendezett oszlop értéke eltér-e az előző sor rendezett oszlopának értékétől. Ha igen, be kell szúrnunk egy új GridViewRow példányt a vezérlőhierarchiába. Ez a következő kóddal történik:
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
Ez a kód azzal kezdődik, hogy programozott módon hivatkozik a Table GridView vezérlőhierarchiájának gyökerében található objektumra, és létrehoz egy nevű lastValuekarakterlánc-változót.
lastValue az aktuális sor rendezett oszlopának és az előző sor értékének összehasonlítására szolgál. Ezután a rendszer felsorolja a GridView s Rows gyűjteményt, és minden sorhoz a rendezett oszlop értékét tárolja a currentValue változóban.
Megjegyzés:
Az adott sor rendezett oszlopának értékének meghatározásához a cella s Text tulajdonságát használom. Ez jól működik a BoundFields esetében, de nem működik a kívánt módon a TemplateFields, CheckBoxFields stb. esetében. Hamarosan megvizsgáljuk, hogyan lehet figyelembe venni az alternatív GridView mezőket.
Ezután összehasonlítjuk az currentValue és lastValue változókat. Ha eltérnek, új elválasztó sort kell hozzáadnunk a vezérlőhierarchiához. Ez úgy érhető el, hogy meghatározzuk az objektum GridViewRow gyűjteményének indexét TableRows, új GridViewRow és példányokat TableCell hozunk létre, majd hozzáadjuk az TableCell és a GridViewRow vezérlőhierarchiához.
Vegye figyelembe, hogy az elválasztó sor egyedül TableCell úgy van formázva, hogy a GridView teljes szélességét lefedje, a SortHeaderRowStyle CSS osztállyal van formázva, és olyan tulajdonsággal Text rendelkezik, hogy a rendezési csoport nevét (például Kategória ) és a csoport értékét (például Italok) is megjeleníti. Végül lastValuecurrentValuea .
A rendezési csoport fejlécsorának SortHeaderRowStyle formázásához használt CSS osztályt meg kell adni a Styles.css fájlban. Nyugodtan használja az Ön számára tetsző stílusbeállításokat; A következőket használtam:
.SortHeaderRowStyle
{
background-color: #c00;
text-align: left;
font-weight: bold;
color: White;
}
Az aktuális kóddal a rendezési felület rendezési csoportfejléceket ad hozzá bármely kötött mező szerinti rendezéskor (lásd az 5. ábrát, amely egy képernyőképet mutat a szállító szerinti rendezéskor). Ha azonban bármely más mezőtípus (például CheckBoxField vagy TemplateField) szerint rendez, a rendezési csoport fejlécei sehol sem találhatók (lásd a 6. ábrát).
5. ábra: A rendezési felület tartalmazza a csoportfejlécek rendezését a BoundFields szerinti rendezéskor (kattintson a teljes méretű kép megtekintéséhez)
6. ábra: Hiányoznak a rendezési csoport fejlécei a CheckBoxField rendezésekor (kattintson a teljes méretű kép megtekintéséhez)
A rendezési csoportfejlécek azért hiányoznak a CheckBoxField szerinti rendezéskor, mert a kód jelenleg csak az s TableCell tulajdonságot Text használja az egyes sorok rendezett oszlopának értékének meghatározásához. A CheckBoxFields esetében az TableCell s Text tulajdonság egy üres karakterlánc, ehelyett az érték az s TableCell gyűjteményben található Controls CheckBox webes vezérlőn keresztül érhető el.
A BoundFields mezőktől eltérő mezőtípusok kezeléséhez ki kell egészítenünk azt a kódot, amelyhez a currentValue változó hozzá van rendelve, hogy ellenőrizzük, van-e CheckBox TableCell az s Controls gyűjteményben. A használata currentValue = gvr.Cells(sortColumnIndex).Texthelyett cserélje le ezt a kódot a következőre:
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
Ez a kód megvizsgálja az aktuális sor rendezett oszlopát TableCell , és megállapítja, hogy vannak-e vezérlők a gyűjteményben Controls . Ha vannak, és az első vezérlő egy CheckBox, a currentValue változó értéke Igen vagy Nem lesz, a CheckBox s Checked tulajdonságától függően. Ellenkező esetben az értéket az TableCell s Text tulajdonságból vesszük. Ez a logika replikálható a GridView-ban esetlegesen létező TemplateFields rendezésének kezelésére.
A fenti kód hozzáadásával a rendezési csoportok fejlécei most már jelen vannak a megszűnt CheckBoxField szerinti rendezéskor (lásd a 7. ábrát).
7. ábra: A rendezési csoport fejlécei most már jelen vannak a CheckBoxField rendezésekor (kattintson a teljes méretű kép megtekintéséhez)
Megjegyzés:
Ha vannak olyan termékei, amelyek NULL adatbázis-értékei a CategoryID, SupplierIDvagy UnitPrice mezőkhöz, akkor ezek az értékek alapértelmezés szerint üres karakterláncként jelennek meg a GridView-ban, ami azt jelenti, hogy az elválasztó sor szövege az értékekkel rendelkező NULL termékeknél a következőképpen hangzik: (azaz nincs név a Kategória után: mint a Kategória: Italok esetében). Ha itt szeretne megjeleníteni egy értéket, beállíthatja a BoundFields NullDisplayText tulajdonságot a megjeleníteni kívánt szövegre, vagy hozzáadhat egy feltételes utasítást a Render metódushoz, amikor az currentValue elválasztó sor s Text tulajdonságához rendeli.
Összefoglalás
A GridView nem tartalmaz sok beépített lehetőséget a rendezési felület testreszabásához. Egy kis alacsony szintű kóddal azonban lehetőség van a GridView vezérlőhierarchiájának módosítására, hogy testreszabottabb felületet hozzon létre. Ebben az oktatóanyagban láthattuk, hogyan adhatunk hozzá rendezési csoportelválasztó sort egy rendezhető GridView-hoz, amely könnyebben azonosítja a különböző csoportokat és a csoportok határait. A testreszabott rendezési felületek további példáiért tekintse meg Scott GuthrieA Few ASP.NET 2.0 GridView rendezési tippek és trükkök blogbejegyzését .
Boldog programozást!
Tudnivalók a szerzőről
Scott Mitchell, hét ASP/ASP.NET-könyv szerzője és a 4GuysFromRolla.com alapítója, 1998 óta dolgozik a Microsoft webtechnológiáival. Scott független tanácsadóként, edzőként és íróként dolgozik. Legújabb könyve Sams Tanuld meg ASP.NET 2.0 24 óra alatt. Ő itt elérhető mitchell@4GuysFromRolla.com.