Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
door Scott Mitchell
Wanneer u een lange lijst met gesorteerde gegevens weergeeft, kan het handig zijn om gerelateerde gegevens te groeperen door scheidingstekens te introduceren. In deze zelfstudie ziet u hoe u een dergelijke gebruikersinterface voor sorteren maakt.
Introductie
Bij het weergeven van een lange lijst met gesorteerde gegevens waarbij er slechts een handvol verschillende waarden in de gesorteerde kolom staan, kan een eindgebruiker het moeilijk vinden om te bepalen waar, precies, de verschilgrenzen voorkomen. Er zijn bijvoorbeeld 81 producten in de database, maar slechts negen verschillende categoriekeuzen (acht unieke categorieën plus de NULL
optie). Overweeg het geval van een gebruiker die geïnteresseerd is in het onderzoeken van de producten die onder de categorie Zeevruchten vallen. Op een pagina met alle producten in één GridView kan de gebruiker besluiten om de resultaten te sorteren op categorie, die alle visproducten samen zal groeperen. Na het sorteren op categorie moet de gebruiker vervolgens door de lijst zoeken, op zoek naar waar de producten met visgroepen beginnen en eindigen. Omdat de resultaten alfabetisch zijn gesorteerd op de categorienaam, is het niet moeilijk om de zeevruchtenproducten te vinden, maar het vereist nog steeds het nauwkeurig doorzoeken van de lijst met items in het raster.
Om de grenzen tussen gesorteerde groepen te benadrukken, maken veel websites gebruik van een gebruikersinterface waarmee een scheidingsteken tussen dergelijke groepen wordt toegevoegd. Met scheidingstekens zoals in afbeelding 1 kan een gebruiker sneller een bepaalde groep vinden en de grenzen identificeren, en bepalen welke afzonderlijke groepen in de gegevens bestaan.
Afbeelding 1: Elke categoriegroep is duidelijk geïdentificeerd (klik om de afbeelding op volledige grootte weer te geven)
In deze zelfstudie ziet u hoe u een dergelijke gebruikersinterface voor sorteren maakt.
Stap 1: Een standaard, sorteerbare rasterweergave maken
Voordat we de GridView uitbreiden om de verbeterde sorteerinterface te bieden, gaan we eerst een standaard, sorteerbare GridView maken waarin de producten worden vermeld. Open eerst de CustomSortingUI.aspx
pagina in de PagingAndSorting
map. Voeg een GridView toe aan de pagina, stel de ID
eigenschap in op ProductList
, en koppel deze aan een nieuwe ObjectDataSource. Configureer de ObjectDataSource om de ProductsBLL
klasse GetProducts()
methode te gebruiken voor het selecteren van records.
Configureer vervolgens de GridView zodanig dat deze alleen de ProductName
, CategoryName
, en SupplierName
UnitPrice
BoundFields en het Stopgezette SelectievakjeVeld bevat. Ten slotte configureert u de GridView om sorteren te ondersteunen door het selectievakje 'Sorteren inschakelen' aan te vinken in de smarttag van de GridView (of door de eigenschap ervan AllowSorting
in te true
stellen). Nadat u deze toevoegingen aan de CustomSortingUI.aspx
pagina hebt gemaakt, moet de declaratieve markering er ongeveer als volgt uitzien:
<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>
Neem even de tijd om onze voortgang tot nu toe in een browser te bekijken. In afbeelding 2 ziet u de sorteerbare GridView wanneer de gegevens op categorie in alfabetische volgorde worden gesorteerd.
Afbeelding 2: De sorteerbare rasterweergavegegevens zijn gesorteerd op categorie (klik om de afbeelding op volledige grootte weer te geven)
Stap 2: Technieken voor het toevoegen van de scheidingstekenrijen verkennen
Nu de algemene, sorteerbare GridView is voltooid, hoeft u alleen de scheidingstekenrijen in de GridView toe te voegen vóór elke unieke gesorteerde groep. Maar hoe kunnen dergelijke rijen worden geïnjecteerd in de GridView? In wezen moeten we de rijen van GridView doorlopen, bepalen waar de verschillen optreden tussen de waarden in de gesorteerde kolom en vervolgens de juiste scheidingstekenrij toevoegen. Wanneer u nadenkt over dit probleem, lijkt het natuurlijk dat de oplossing zich ergens in de gebeurtenis-handler van RowDataBound
GridView bevindt. Zoals we hebben besproken in de zelfstudie Aangepaste opmaak op basis van gegevens , wordt deze gebeurtenis-handler vaak gebruikt bij het toepassen van opmaak op rijniveau op basis van de gegevens van de rij. De RowDataBound
gebeurtenis-handler is hier echter niet de oplossing, omdat rijen niet programmatisch vanuit deze gebeurtenis-handler aan GridView kunnen worden toegevoegd. De GridView-collectie is eigenlijk alleen-lezen.
Als u extra rijen wilt toevoegen aan de GridView, hebt u drie opties:
- Voeg deze rijen voor metagegevensscheidingstekens toe aan de werkelijke gegevens die zijn gebonden aan de GridView
- Nadat de GridView is gebonden aan de gegevens, voegt u extra
TableRow
exemplaren toe aan de verzameling besturingselementen van GridView - Een aangepast serverbesturingselement maken dat het GridView-besturingselement uitbreidt en deze methoden overschrijft die verantwoordelijk zijn voor het maken van de structuur van GridView
Het maken van een aangepast serverbeheer is de beste benadering als deze functionaliteit nodig was op veel webpagina's of op verschillende websites. Het zou echter nogal wat code met zich meebrengen en een grondige verkenning van de diepten van de interne werking van GridView. Daarom wordt deze optie voor deze zelfstudie niet overwogen.
De andere twee opties waarmee scheidingstekenrijen worden toegevoegd aan de werkelijke gegevens die zijn gebonden aan de GridView en het bewerken van de verzameling besturingselementen van GridView nadat deze gebonden zijn, vallen het probleem anders aan en verdienen een discussie.
Rijen toevoegen aan de gegevens die zijn gebonden aan de GridView
Wanneer GridView is gebonden aan een gegevensbron, wordt er een GridViewRow
gemaakt voor elke record die door de gegevensbron wordt geretourneerd. Daarom kunnen we de benodigde scheidingstekenrijen injecteren door scheidingstekenrecords toe te voegen aan de gegevensbron voordat deze aan de GridView worden gekoppeld. In afbeelding 3 ziet u dit concept.
Afbeelding 3: Eén techniek omvat het toevoegen van scheidingsrijen aan de gegevensbron
Ik gebruik de term 'scheidingsrecords' tussen aanhalingstekens omdat er geen speciaal scheidingsrecord is; in plaats daarvan moeten we op een of andere manier aangeven dat een bepaald record in de gegevensbron fungeert als scheiding in plaats van een normale gegevensrij. Voor onze voorbeelden koppelen we een ProductsDataTable
instantie aan de GridView, die bestaat uit ProductRows
. We kunnen een record markeren als een scheidingstekenrij door de eigenschap CategoryID
op -1
te zetten (aangezien een dergelijke waarde normaal niet zou kunnen bestaan).
Als u deze techniek wilt gebruiken, moet u de volgende stappen uitvoeren:
- De gegevens programmatisch ophalen om verbinding te maken met gridview (een
ProductsDataTable
exemplaar) - De gegevens sorteren op basis van de GridView-s
SortExpression
enSortDirection
-eigenschappen - Zoek door de
ProductsRows
naar verschillen in de gesorteerdeProductsDataTable
kolom, en zoek waar deze verschillen zich bevinden. - Injecteer bij elke groepsgrenswaarde een exemplaar van een scheidingstekenrecord
ProductsRow
in de gegevenstabel, een exemplaar waaropCategoryID
is ingesteld op-1
(of op welke aanduiding is besloten om een scheidingstekenrecord te markeren) - Nadat u de scheidingstekenrijen hebt geïnjecteerd, verbindt u de gegevens programmatisch met gridView
Naast deze vijf stappen moeten we ook een gebeurtenis-handler opgeven voor de GridView-gebeurtenis RowDataBound
. Hier controleren we elk DataRow
en bepalen we of het een scheidingsrij was, waarbij de instelling van CategoryID
-1
was. Zo ja, dan willen we waarschijnlijk de opmaak of de tekst aanpassen die in de cel(en) wordt weergegeven.
Als u deze techniek gebruikt voor het injecteren van de sorteergroepgrenzen, is iets meer werk vereist dan hierboven is beschreven, omdat u ook een gebeurtenis-handler moet opgeven voor de gridView-gebeurtenis Sorting
en de SortExpression
waarden SortDirection
moet bijhouden.
De verzameling besturingselementen van GridView bewerken nadat het gegevensgebonden is
In plaats van de gegevens te verzenden voordat deze aan GridView worden gekoppeld, kunnen we de scheidingstekenrijen toevoegen nadat de gegevens zijn gebonden aan de GridView. Het proces van gegevensbinding bouwt de besturingshiërarchie van GridView op, wat in werkelijkheid gewoon een Table
exemplaar is dat bestaat uit een verzameling rijen, die elk bestaat uit een verzameling cellen. Met name bevat de verzameling besturingselementen van GridView een Table
object in de hoofddirectory, een GridViewRow
(die is afgeleid van de TableRow
klasse) voor iedere record in de DataSource
gebonden aan de GridView en een TableCell
object in elke GridViewRow
instantie voor elk gegevensveld in het DataSource
.
Als u scheidingstekenrijen tussen elke sorteergroep wilt toevoegen, kunnen we deze besturingshiërarchie rechtstreeks bewerken zodra deze is gemaakt. We kunnen er zeker van zijn dat de besturingshiërarchie van GridView voor de laatste keer is gemaakt op het moment dat de pagina wordt weergegeven. Daarom overschrijft deze methode de Page
klasse s Render
methode, waarbij de uiteindelijke controlehiërarchie van de GridView wordt bijgewerkt om de benodigde scheidingsrijen op te nemen. In afbeelding 4 ziet u dit proces.
Afbeelding 4: Met een alternatieve techniek wordt de besturingshiërarchie van GridView bewerkt (klik om de afbeelding op volledige grootte weer te geven)
Voor deze zelfstudie gebruiken we deze laatste benadering om de gebruikerservaring voor sorteren aan te passen.
Opmerking
De code die ik in deze handleiding laat zien, is gebaseerd op het voorbeeld in het blogbericht van Teemu Keiski, Een beetje spelen met GridView Sort Grouping.
Stap 3: De scheidingstekenrijen toevoegen aan de hiërarchie van rasterweergave
Omdat we de scheidingstekenrijen pas willen toevoegen aan de besturingshiërarchie van GridView nadat deze is aangemaakt en voor de laatste keer tijdens dat paginabezoek is aangemaakt, willen we deze toevoeging uitvoeren aan het einde van de levenscyclus van de pagina, maar voordat de daadwerkelijke GridView-besturingshiërarchie in HTML is weergegeven. Het laatste mogelijke punt waarop we dit kunnen doen, is de Page
klasse s Render
gebeurtenis, die we in onze code-behind-klasse kunnen overschrijven met behulp van de volgende methode-handtekening.
Protected Overrides Sub Render(ByVal writer As HtmlTextWriter)
' Add code to manipulate the GridView control hierarchy
MyBase.Render(writer)
End Sub
Wanneer de oorspronkelijke Page
methode van de Render
klasse wordt aangeroepenbase.Render(writer)
, worden alle besturingselementen op de pagina weergegeven, waardoor de markeringen worden gegenereerd op basis van hun besturingshiërarchie. Daarom is het noodzakelijk dat we beide aanroepen base.Render(writer)
, zodat de pagina wordt weergegeven en dat we de besturingshiërarchie van GridView bewerken vóór het aanroepen base.Render(writer)
, zodat de scheidingstekenrijen zijn toegevoegd aan de besturingshiërarchie van GridView voordat deze wordt weergegeven.
Als u de kopteksten van de sorteergroep wilt injecteren, moet u eerst controleren of de gebruiker heeft gevraagd of de gegevens moeten worden gesorteerd. De inhoud van GridView is standaard niet gesorteerd en daarom hoeven we geen groepssorteringskoppen in te voeren.
Opmerking
Als u wilt dat de GridView wordt gesorteerd op een bepaalde kolom wanneer de pagina voor het eerst wordt geladen, roept u de methode GridView Sort
aan op het eerste paginabezoek (maar niet op volgende postbacks). Doe dit door deze aanroep toe te voegen aan de Page_Load
gebeurtenishandler binnen een if (!Page.IsPostBack)
voorwaardelijke structuur. Raadpleeg de handleiding Over paging- en sorteerrapportgegevens voor aanvullende informatie over de Sort
methode.
Ervan uitgaande dat de gegevens zijn gesorteerd, is onze volgende taak om te bepalen op welke kolom de gegevens zijn gesorteerd en vervolgens de rijen te scannen die zoeken naar verschillen in de waarden van die kolom. De volgende code zorgt ervoor dat de gegevens zijn gesorteerd en de kolom worden gevonden waarop de gegevens zijn gesorteerd:
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
Als de GridView nog moet worden gesorteerd, is de eigenschap GridView SortExpression
niet ingesteld. Daarom willen we alleen de scheidingstekenrijen toevoegen als deze eigenschap een bepaalde waarde heeft. Als dit het geval is, moeten we vervolgens de index van de kolom bepalen waarop de gegevens zijn gesorteerd. Dit wordt bereikt door de Columns
verzameling van GridView te doorlopen en te zoeken naar de kolom waarvan SortExpression
de eigenschap gelijk is aan de eigenschap van GridView SortExpression
. Naast de kolomindex nemen we ook de HeaderText
eigenschap mee, die wordt gebruikt bij het weergeven van de scheidingsrijen.
Met de index van de kolom waarop de gegevens worden gesorteerd, is de laatste stap het inventariseren van de rijen van de GridView. Voor elke rij moeten we bepalen of de waarde van de gesorteerde kolom verschilt van de waarde van de vorige rij gesorteerde kolom. Als dat het geval is, moeten we een nieuw GridViewRow
exemplaar in de besturingshiërarchie injecteren. Dit wordt bereikt met de volgende code:
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
Deze code begint met het programmatisch verwijzen naar het Table
object dat is gevonden in de hoofdmap van de besturingshiërarchie van GridView en het maken van een tekenreeksvariabele met de naam lastValue
.
lastValue
wordt gebruikt om de gesorteerde kolomwaarde van de huidige rij te vergelijken met de vorige rijwaarde. Vervolgens wordt de verzameling GridView Rows
geïnventariseerd en voor elke rij wordt de waarde van de gesorteerde kolom opgeslagen in de currentValue
variabele.
Opmerking
Als u de waarde van de gesorteerde kolom van de bepaalde rij wilt bepalen, gebruikt u de eigenschap cel Text
. Dit werkt goed voor BoundFields, maar werkt niet naar wens voor TemplateFields, CheckBoxFields, enzovoort. We bekijken hoe u binnenkort rekening moet houden met alternatieve GridView-velden.
De currentValue
variabelen en lastValue
variabelen worden vervolgens vergeleken. Als ze verschillen, moeten we een nieuwe scheidingstekenrij toevoegen aan de besturingshiërarchie. Dit wordt bereikt door de index van GridViewRow
in de Table
objectverzameling Rows
te bepalen, nieuwe GridViewRow
en TableCell
exemplaren te maken, en vervolgens de TableCell
en GridViewRow
aan de besturingshiërarchie toe te voegen.
Houd er rekening mee dat de scheidingstekenrij TableCell
is opgemaakt, zodat deze de volledige breedte van de GridView beslaat, is opgemaakt met behulp van de SortHeaderRowStyle
CSS-klasse en de eigenschap heeft Text
, zodat zowel de sorteergroepnaam (zoals Categorie) als de groepswaarde (zoals Drank) wordt weergegeven. Ten slotte wordt lastValue
bijgewerkt naar de waarde van currentValue
.
De CSS-klasse die wordt gebruikt om de veldnamenrij SortHeaderRowStyle
van de sorteergroep op te maken, moet worden opgegeven in het Styles.css
bestand. U kunt gerust de stijlinstellingen gebruiken die u aanspreekt; Ik heb het volgende gebruikt:
.SortHeaderRowStyle
{
background-color: #c00;
text-align: left;
font-weight: bold;
color: White;
}
Met de huidige code voegt de sorteerinterface sorteergroepkoppen toe bij het sorteren op een BoundField (zie afbeelding 5, waarin een schermopname wordt weergegeven bij het sorteren op leverancier). Wanneer u echter sorteert op een ander veldtype (zoals een CheckBoxField of TemplateField), zijn de kopteksten van de sorteergroep nergens te vinden (zie afbeelding 6).
Afbeelding 5: De sorteerinterface bevat groepsheaders wanneer er wordt gesorteerd op BoundFields (klik om de afbeelding op volledige grootte weer te geven)
Afbeelding 6: De kopteksten van de sorteergroep ontbreken bij het sorteren van een selectievakjeveld (klik om de afbeelding op volledige grootte weer te geven)
De reden waarom de sorteergroepkoppen ontbreken bij het sorteren op een CheckBoxField, is omdat de code momenteel alleen de TableCell
eigenschap s Text
gebruikt om de waarde van de gesorteerde kolom voor elke rij te bepalen. Voor CheckBoxFields is de eigenschap TableCell
s Text
een lege tekenreeks; in plaats daarvan is de waarde beschikbaar via een Selectievakje-webbesturingselement dat zich binnen de verzameling TableCell
bevindt Controls
.
Als u andere veldtypen dan BoundFields wilt verwerken, moet u de code uitbreiden waaraan de currentValue
variabele is toegewezen om te controleren of er een Selectievakje in de TableCell
Controls
verzameling bestaat. In plaats van currentValue = gvr.Cells(sortColumnIndex).Text
, vervang deze code door het volgende:
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
Met deze code wordt de gesorteerde kolom TableCell
voor de huidige rij onderzocht om te bepalen of er besturingselementen in de Controls
verzameling zijn. Als er een selectievakje is en het eerste besturingselement een selectievakje is, is de currentValue
variabele ingesteld op Ja of Nee, afhankelijk van de eigenschap Selectievakje.Checked
Anders wordt de waarde uit de TableCell
eigenschap s Text
genomen. Deze logica kan worden gerepliceerd voor het afhandelen van sortering voor sjabloonvelden die mogelijk aanwezig zijn in de GridView.
Met de bovenstaande code-toevoeging zijn de kopteksten van de sorteergroep nu aanwezig bij het sorteren op het stopgezette selectievakjeveld (zie afbeelding 7).
Afbeelding 7: De kopteksten van de sorteergroep zijn nu aanwezig bij het sorteren van een selectievakjeveld (klik hier om de volledige afbeelding weer te geven)
Opmerking
Als u producten met NULL
databasewaarden voor de CategoryID
, SupplierID
of UnitPrice
velden hebt, worden deze waarden standaard weergegeven als lege tekenreeksen in GridView, wat betekent dat de tekst van de scheidingstekenrij voor die producten met NULL
waarden als Categorie wordt gelezen: (dat wil zeggen, er is geen naam achter Categorie: zoals bij Categorie: Drank). Als u een waarde wilt weergeven, kunt u de eigenschap BoundFields NullDisplayText
instellen op de tekst die u wilt weergeven, of u kunt een voorwaardelijke instructie toevoegen in de Render-methode wanneer u de eigenschap van de currentValue
scheidingsrij Text
toewijst.
Samenvatting
De GridView bevat niet veel ingebouwde opties voor het aanpassen van de sorteerinterface. Met een beetje code op laag niveau is het echter mogelijk om de besturingshiërarchie van GridView aan te passen om een meer aangepaste interface te maken. In deze zelfstudie hebben we gezien hoe u een sorteergroepscheidingstekenrij toevoegt voor een sorteerbare GridView, waarmee de afzonderlijke groepen en die groepsgrenzen gemakkelijker kunnen worden geïdentificeerd. Bekijk het blogbericht Scott Guthrie s A Few ASP.NET 2.0 GridView Sort Tips and Tricks voor aanvullende voorbeelden van aangepaste sorteerinterfaces.
Veel plezier met programmeren!
Over de auteur
Scott Mitchell, auteur van zeven ASP/ASP.NET-boeken en oprichter van 4GuysFromRolla.com, werkt sinds 1998 met Microsoft-webtechnologieën. Scott werkt als onafhankelijk consultant, trainer en schrijver. Zijn laatste boek is Sams Teach Yourself ASP.NET 2.0 in 24 uur. Hij kan worden bereikt op mitchell@4GuysFromRolla.com.