GridView.md
May 18, 2026 · View on GitHub
The GridView component is meant to emulate the asp:GridView control in markup and is defined in the System.Web.UI.WebControls.GridView class
Features supported in Blazor
- Readonly grid
- Bound, Button, Hyperlink, Template, and Command columns
- Paging -
AllowPaging,PageSize,PageIndex,PageIndexChangedevent - Sorting -
AllowSorting,SortExpression,SortDirection,Sorting/Sortedevents - CRUD model binding -
SelectMethod,UpdateMethod,DeleteMethod,DataKeyNames, andGridViewUpdateEventArgs.Keys/NewValues - Row Editing -
EditIndex,RowEditing,RowUpdating,RowDeleting,RowCancelingEditevents - Selection -
SelectedIndex,SelectedRow,SelectedValue,AutoGenerateSelectButton,SelectedIndexChanging/SelectedIndexChangedevents - Style Sub-Components -
RowStyle,AlternatingRowStyle,HeaderStyle,FooterStyle,SelectedRowStyle,EditRowStyle,EmptyDataRowStyle,PagerStyle - Display Properties -
ShowHeader,ShowFooter,Caption,CaptionAlign,EmptyDataTemplate,GridLines,UseAccessibleHeader,CellPadding,CellSpacing,ShowHeaderWhenEmpty ToolTip- tooltip text displayed on hover (renders astitleattribute)
Blazor Notes
- The
RowCommand.CommandSourceobject will be populated with theButtonFieldobject - Context attribute - When using
<TemplateField>, addContext="Item"to access the current row item as@Iteminstead of Blazor's default@context - ItemType cascading - The
ItemTypeparameter is automatically cascaded from the GridView to child columns. You only need to specify it once on the GridView, and all child columns (BoundField, TemplateField, HyperLinkField, ButtonField, CommandField) will automatically infer the type. For backward compatibility, you can still explicitly specifyItemTypeon individual columns if desired. - CRUD model binding -
UpdateMethodandDeleteMethodnow participate in the built-in GridView command flow. When a row update fires,GridViewUpdateEventArgs.Keys,OldValues, andNewValuesare populated forBoundFieldcolumns, whileDataKeyNamesvalues are forwarded to string-basedUpdateMethod/DeleteMethodhandlers. - Paging - When
AllowPaging="true", the GridView automatically paginates the data source usingSkip()/Take(). A numeric pager is rendered below the grid. ThePageIndexChangedevent fires with aPageChangedEventArgscontainingNewPageIndex,OldPageIndex,TotalPages,StartRowIndex, andCancel. - Sorting - When
AllowSorting="true", column headers become clickable. You must handle theSortingevent to apply the sort to your data source. TheSortedevent fires after the sort completes. Both events useGridViewSortEventArgswithSortExpression,SortDirection, andCancelproperties. - Row Editing - Set
EditIndexto the zero-based row index to put a row in edit mode (-1means no row is being edited). Use<CommandField ShowEditButton="true" />and<CommandField ShowDeleteButton="true" />to preserve Web Forms command-column positions while still using BWFC row events and CRUD methods. - Selection - Set
SelectedIndexto highlight a row.SelectedRowreturns the data item for the selected row, andSelectedValuereturns theDataKeyNamesvalue. WhenAutoGenerateSelectButton="true", a "Select" link column is added automatically. TheSelectedIndexChangingevent fires before the selection changes (cancellable), andSelectedIndexChangedfires after. - Style Sub-Components - Use
<RowStyle>,<AlternatingRowStyle>,<HeaderStyle>,<FooterStyle>,<SelectedRowStyle>,<EditRowStyle>,<EmptyDataRowStyle>, and<PagerStyle>child components to configureTableItemStyleproperties (CssClass, BackColor, ForeColor, etc.) for each section of the grid. - Display Properties -
ShowHeaderandShowFootertoggle header/footer rows.CaptionandCaptionAlignadd a<caption>element.GridLinescontrols table borders.UseAccessibleHeaderrenders<th>withscope="col".CellPaddingandCellSpacingset table spacing.ShowHeaderWhenEmptyshows column headers even when the data source is empty.EmptyDataTemplaterenders custom content when there are no data rows.
!!! warning "Differences from Web Forms"
- PageIndexChanging is not implemented; use PageIndexChanged with the Cancel property instead.
- PagerTemplate is not yet supported; only the built-in numeric pager is available.
- Sorting does not automatically re-sort the data source; you must handle the Sorting event and apply the sort yourself.
- SelectedIndexChanging uses GridViewSelectEventArgs with a Cancel property to prevent selection.
Syntax Comparison
Currently, not every syntax element of Web Forms GridView is supported. In the meantime, the following GridView in Blazor syntax will only include the implemented ones. Non-implemented elements will be included later.
=== "Web Forms"
```html
<asp:GridView
AccessKey="string"
AllowPaging="True|False"
AllowSorting="True|False"
AutoGenerateColumns="True|False"
AutoGenerateDeleteButton="True|False"
AutoGenerateEditButton="True|False"
AutoGenerateSelectButton="True|False"
BackColor="color name|#dddddd"
BackImageUrl="uri"
BorderColor="color name|#dddddd"
BorderStyle="NotSet|None|Dotted|Dashed|Solid|Double|Groove|Ridge|
Inset|Outset"
BorderWidth="size"
Caption="string"
CaptionAlign="NotSet|Top|Bottom|Left|Right"
CellPadding="integer"
CellSpacing="integer"
CssClass="string"
DataKeyNames="string"
DataMember="string"
DataSource="string"
DataSourceID="string"
EditIndex="integer"
EmptyDataText="string"
Enabled="True|False"
EnableSortingAndPagingCallbacks="True|False"
EnableTheming="True|False"
EnableViewState="True|False"
Font-Bold="True|False"
Font-Italic="True|False"
Font-Names="string"
Font-Overline="True|False"
Font-Size="string|Smaller|Larger|XX-Small|X-Small|Small|Medium|
Large|X-Large|XX-Large"
Font-Strikeout="True|False"
Font-Underline="True|False"
ForeColor="color name|#dddddd"
GridLines="None|Horizontal|Vertical|Both"
Height="size"
HorizontalAlign="NotSet|Left|Center|Right|Justify"
ID="string"
OnDataBinding="DataBinding event handler"
OnDataBound="DataBound event handler"
OnDisposed="Disposed event handler"
OnInit="Init event handler"
OnLoad="Load event handler"
OnPageIndexChanged="PageIndexChanged event handler"
OnPageIndexChanging="PageIndexChanging event handler"
OnPreRender="PreRender event handler"
OnRowCancelingEdit="RowCancelingEdit event handler"
OnRowCommand="RowCommand event handler"
OnRowCreated="RowCreated event handler"
OnRowDataBound="RowDataBound event handler"
OnRowDeleted="RowDeleted event handler"
OnRowDeleting="RowDeleting event handler"
OnRowEditing="RowEditing event handler"
OnRowUpdated="RowUpdated event handler"
OnRowUpdating="RowUpdating event handler"
OnSelectedIndexChanged="SelectedIndexChanged event handler"
OnSelectedIndexChanging="SelectedIndexChanging event handler"
OnSorted="Sorted event handler"
OnSorting="Sorting event handler"
OnUnload="Unload event handler"
PageIndex="integer"
PagerSettings-FirstPageImageUrl="uri"
PagerSettings-FirstPageText="string"
PagerSettings-LastPageImageUrl="uri"
PagerSettings-LastPageText="string"
PagerSettings-Mode="NextPrevious|Numeric|NextPreviousFirstLast|
NumericFirstLast"
PagerSettings-NextPageImageUrl="uri"
PagerSettings-NextPageText="string"
PagerSettings-PageButtonCount="integer"
PagerSettings-Position="Bottom|Top|TopAndBottom"
PagerSettings-PreviousPageImageUrl="uri"
PagerSettings-PreviousPageText="string"
PagerSettings-Visible="True|False"
PageSize="integer"
RowHeaderColumn="string"
runat="server"
SelectedIndex="integer"
ShowFooter="True|False"
ShowHeader="True|False"
SkinID="string"
Style="string"
TabIndex="integer"
ToolTip="string"
UseAccessibleHeader="True|False"
Visible="True|False"
Width="size"
>
<AlternatingRowStyle />
<Columns>
<asp:BoundField
AccessibleHeaderText="string"
ApplyFormatInEditMode="True|False"
ConvertEmptyStringToNull="True|False"
DataField="string"
DataFormatString="string"
FooterText="string"
HeaderImageUrl="uri"
HeaderText="string"
HtmlEncode="True|False"
InsertVisible="True|False"
NullDisplayText="string"
ReadOnly="True|False"
ShowHeader="True|False"
SortExpression="string"
Visible="True|False"
>
<ControlStyle />
<FooterStyle />
<HeaderStyle />
<ItemStyle />
</asp:BoundField>
<asp:ButtonField
AccessibleHeaderText="string"
ButtonType="Button|Image|Link"
CausesValidation="True|False"
CommandName="string"
DataTextField="string"
DataTextFormatString="string"
FooterText="string"
HeaderImageUrl="uri"
HeaderText="string"
ImageUrl="uri"
InsertVisible="True|False"
ShowHeader="True|False"
SortExpression="string"
Text="string"
ValidationGroup="string"
Visible="True|False"
>
<ControlStyle />
<FooterStyle />
<HeaderStyle />
<ItemStyle />
</asp:ButtonField>
<asp:CheckBoxField
AccessibleHeaderText="string"
DataField="string"
FooterText="string"
HeaderImageUrl="uri"
HeaderText="string"
InsertVisible="True|False"
ReadOnly="True|False"
ShowHeader="True|False"
SortExpression="string"
Text="string"
Visible="True|False"
>
<ControlStyle />
<FooterStyle />
<HeaderStyle />
<ItemStyle />
</asp:CheckBoxField>
<asp:CommandField
AccessibleHeaderText="string"
ButtonType="Button|Image|Link"
CancelImageUrl="uri"
CancelText="string"
CausesValidation="True|False"
DeleteImageUrl="uri"
DeleteText="string"
EditImageUrl="uri"
EditText="string"
FooterText="string"
HeaderImageUrl="uri"
HeaderText="string"
InsertImageUrl="uri"
InsertText="string"
InsertVisible="True|False"
NewImageUrl="uri"
NewText="string"
SelectImageUrl="uri"
SelectText="string"
ShowCancelButton="True|False"
ShowDeleteButton="True|False"
ShowEditButton="True|False"
ShowHeader="True|False"
ShowInsertButton="True|False"
ShowSelectButton="True|False"
SortExpression="string"
UpdateImageUrl="uri"
UpdateText="string"
ValidationGroup="string"
Visible="True|False"
>
<ControlStyle />
<FooterStyle />
<HeaderStyle />
<ItemStyle />
</asp:CommandField>
<asp:DynamicField
AccessibleHeaderText="string"
ApplyFormatInEditMode="True|False"
ConvertEmptyStringToNull="True|False"
DataField="string"
DataFormatString="string"
FooterText="string"
HeaderImageUrl="uri"
HeaderText="string"
HtmlEncode="True|False"
InsertVisible="True|False"
NullDisplayText="string"
ShowHeader="True|False"
UIHint="string"
Visible="True|False"
>
<ControlStyle />
<FooterStyle />
<HeaderStyle />
<ItemStyle />
</asp:DynamicField>
<asp:HyperLinkField
AccessibleHeaderText="string"
DataNavigateUrlFields="string"
DataNavigateUrlFormatString="string"
DataTextField="string"
DataTextFormatString="string"
FooterText="string"
HeaderImageUrl="uri"
HeaderText="string"
InsertVisible="True|False"
NavigateUrl="uri"
ShowHeader="True|False"
SortExpression="string"
Target="string|_blank|_parent|_search|_self|_top"
Text="string"
Visible="True|False"
>
<ControlStyle />
<FooterStyle />
<HeaderStyle />
<ItemStyle />
</asp:HyperLinkField>
<asp:ImageField
AccessibleHeaderText="string"
AlternateText="string"
ConvertEmptyStringToNull="True|False"
DataAlternateTextField="string"
DataAlternateTextFormatString="string"
DataImageUrlField="string"
DataImageUrlFormatString="string"
FooterText="string"
HeaderImageUrl="uri"
HeaderText="string"
InsertVisible="True|False"
NullDisplayText="string"
NullImageUrl="uri"
ReadOnly="True|False"
ShowHeader="True|False"
SortExpression="string"
Visible="True|False"
>
<ControlStyle />
<FooterStyle />
<HeaderStyle />
<ItemStyle />
</asp:ImageField>
<asp:TemplateField
AccessibleHeaderText="string"
ConvertEmptyStringToNull="True|False"
FooterText="string"
HeaderImageUrl="uri"
HeaderText="string"
InsertVisible="True|False"
ShowHeader="True|False"
SortExpression="string"
Visible="True|False"
>
<ControlStyle />
<FooterStyle />
<HeaderStyle />
<ItemStyle />
<AlternatingItemTemplate>
<!-- child controls -->
</AlternatingItemTemplate>
<EditItemTemplate>
<!-- child controls -->
</EditItemTemplate>
<FooterTemplate>
<!-- child controls -->
</FooterTemplate>
<HeaderTemplate>
<!-- child controls -->
</HeaderTemplate>
<InsertItemTemplate>
<!-- child controls -->
</InsertItemTemplate>
<ItemTemplate>
<!-- child controls -->
</ItemTemplate>
</asp:TemplateField>
</Columns>
<EditRowStyle />
<EmptyDataRowStyle />
<EmptyDataTemplate>
<!-- child controls -->
</EmptyDataTemplate>
<FooterStyle />
<HeaderStyle />
<PagerSettings
FirstPageImageUrl="uri"
FirstPageText="string"
LastPageImageUrl="uri"
LastPageText="string"
Mode="NextPrevious|Numeric|NextPreviousFirstLast|
NumericFirstLast"
NextPageImageUrl="uri"
NextPageText="string"
OnPropertyChanged="PropertyChanged event handler"
PageButtonCount="integer"
Position="Bottom|Top|TopAndBottom"
PreviousPageImageUrl="uri"
PreviousPageText="string"
Visible="True|False"
/>
<PagerStyle />
<PagerTemplate>
<!-- child controls -->
</PagerTemplate>
<RowStyle />
<SelectedRowStyle />
</asp:GridView>
```
=== "Blazor"
```html
<GridView
runat="server"
AllowPaging=bool
AllowSorting=bool
AutoGenerateColumns=bool
AutoGenerateSelectButton=bool
Caption=string
CaptionAlign=TableCaptionAlign
CellPadding=int
CellSpacing=int
CssClass=string
DataKeyNames=string
DataSource=IEnumerable
EditIndex=int
EmptyDataText=string
Enabled=bool
GridLines=GridLines
ID=string
Items=IEnumerable
ItemType=Type
OnDataBinding=EventCallBack
OnDataBound=EventCallBack
OnItemDataBound=EventCallBack
OnInit=EventCallBack
OnLoad=EventCallBack
OnPreRender=EventCallBack
OnUnload=EventCallBack
OnDisposed=EventCallBack
PageIndex=int
PageIndexChanged=EventCallBack<PageChangedEventArgs>
PageSize=int
RowCancelingEdit=EventCallBack<GridViewCancelEditEventArgs>
RowDeleting=EventCallBack<GridViewDeleteEventArgs>
RowEditing=EventCallBack<GridViewEditEventArgs>
RowUpdating=EventCallBack<GridViewUpdateEventArgs>
SelectedIndex=int
SelectedIndexChanged=EventCallBack<int>
SelectedIndexChanging=EventCallBack<GridViewSelectEventArgs>
SelectMethod=SelectHandler
ShowFooter=bool
ShowHeader=bool
ShowHeaderWhenEmpty=bool
SortDirection=SortDirection
SortExpression=string
Sorted=EventCallBack<GridViewSortEventArgs>
Sorting=EventCallBack<GridViewSortEventArgs>
TabIndex=int
UseAccessibleHeader=bool
Visible=bool
>
<AlternatingRowStyle CssClass="string" BackColor="WebColor" ... />
<Columns>
<!-- Note: ItemType is optional on columns and will be automatically
inferred from the parent GridView. You can still explicitly
specify ItemType on individual columns for clarity if desired. -->
<BoundField
DataField=string
DataFormatString=string
HeaderText=string
ItemType=Type (optional, inferred from parent)
Visible=bool
>
</BoundField>
<HyperLinkField
AccessibleHeaderText="string"
DataNavigateUrlFields="string"
DataNavigateUrlFormatString="string"
DataTextField="string"
DataTextFormatString="string"
HeaderText="string"
ItemType=Type (optional, inferred from parent)
NavigateUrl="uri"
Target="string|_blank|_parent|_search|_self|_top"
Text="string"
Visible="True|False">
</HyperLinkField>
<TemplateField
HeaderText=string
ItemType=Type (optional, inferred from parent)
Visible=bool
>
<ItemTemplate Context="Item">
<!-- Child Content -->
<ItemTemplate>
</TemplateField>
</Columns>
<EditRowStyle CssClass="string" BackColor="WebColor" ... />
<EmptyDataRowStyle CssClass="string" BackColor="WebColor" ... />
<EmptyDataTemplate>
<!-- Custom content when no data rows -->
</EmptyDataTemplate>
<FooterStyle CssClass="string" BackColor="WebColor" ... />
<HeaderStyle CssClass="string" BackColor="WebColor" ... />
<PagerStyle CssClass="string" BackColor="WebColor" ... />
<RowStyle CssClass="string" BackColor="WebColor" ... />
<SelectedRowStyle CssClass="string" BackColor="WebColor" ... />
</GridView>
```
Examples
Basic Paging
@* GridView with paging enabled, 5 items per page *@
<GridView DataSource="@Products"
ItemType="Product"
AllowPaging="true"
PageSize="5"
PageIndexChanged="HandlePageChanged"
AutoGenerateColumns="true" />
<p>Page @(currentPageIndex + 1)</p>
@code {
private List<Product> Products = new();
private int currentPageIndex = 0;
private void HandlePageChanged(PageChangedEventArgs e)
{
currentPageIndex = e.NewPageIndex;
}
}
Sorting
@* GridView with sortable columns *@
<GridView DataSource="@SortedProducts"
ItemType="Product"
AllowSorting="true"
SortExpression="@sortExpression"
SortDirection="@sortDirection"
Sorting="HandleSorting">
<Columns>
<BoundField DataField="Name" HeaderText="Name" />
<BoundField DataField="Price" HeaderText="Price" DataFormatString="{0:C}" />
</Columns>
</GridView>
@code {
private List<Product> Products = new();
private string sortExpression = "";
private SortDirection sortDirection = SortDirection.Ascending;
private IEnumerable<Product> SortedProducts => sortExpression switch
{
"Name" => sortDirection == SortDirection.Ascending
? Products.OrderBy(p => p.Name)
: Products.OrderByDescending(p => p.Name),
"Price" => sortDirection == SortDirection.Ascending
? Products.OrderBy(p => p.Price)
: Products.OrderByDescending(p => p.Price),
_ => Products
};
private void HandleSorting(GridViewSortEventArgs e)
{
sortExpression = e.SortExpression;
sortDirection = e.SortDirection;
}
}
Row Editing
@* GridView with inline edit, update, delete, and cancel *@
<GridView DataSource="@Products"
ItemType="Product"
EditIndex="@editIndex"
RowEditing="HandleEdit"
RowUpdating="HandleUpdate"
RowDeleting="HandleDelete"
RowCancelingEdit="HandleCancelEdit">
<Columns>
<BoundField DataField="Name" HeaderText="Name" />
<BoundField DataField="Price" HeaderText="Price" DataFormatString="{0:C}" />
</Columns>
</GridView>
@code {
private List<Product> Products = new();
private int editIndex = -1;
private void HandleEdit(GridViewEditEventArgs e)
{
editIndex = e.NewEditIndex;
}
private void HandleUpdate(GridViewUpdateEventArgs e)
{
// Apply changes to Products[e.RowIndex]
editIndex = -1;
}
private void HandleDelete(GridViewDeleteEventArgs e)
{
Products.RemoveAt(e.RowIndex);
editIndex = -1;
}
private void HandleCancelEdit(GridViewCancelEditEventArgs e)
{
editIndex = -1;
}
}
Paging with Sorting
@* Combining paging and sorting *@
<GridView DataSource="@SortedProducts"
ItemType="Product"
AllowPaging="true"
PageSize="10"
PageIndexChanged="HandlePageChanged"
AllowSorting="true"
SortExpression="@sortExpression"
SortDirection="@sortDirection"
Sorting="HandleSorting">
<Columns>
<BoundField DataField="Name" HeaderText="Name" />
<BoundField DataField="Price" HeaderText="Price" DataFormatString="{0:C}" />
</Columns>
</GridView>
@code {
private List<Product> Products = new();
private int currentPageIndex = 0;
private string sortExpression = "";
private SortDirection sortDirection = SortDirection.Ascending;
private IEnumerable<Product> SortedProducts => sortExpression switch
{
"Name" => sortDirection == SortDirection.Ascending
? Products.OrderBy(p => p.Name)
: Products.OrderByDescending(p => p.Name),
"Price" => sortDirection == SortDirection.Ascending
? Products.OrderBy(p => p.Price)
: Products.OrderByDescending(p => p.Price),
_ => Products
};
private void HandlePageChanged(PageChangedEventArgs e)
{
currentPageIndex = e.NewPageIndex;
}
private void HandleSorting(GridViewSortEventArgs e)
{
sortExpression = e.SortExpression;
sortDirection = e.SortDirection;
}
}
Row Selection
@* GridView with row selection and auto-generated select button *@
<GridView DataSource="@Products"
ItemType="Product"
AutoGenerateSelectButton="true"
SelectedIndex="@selectedIndex"
SelectedIndexChanged="HandleSelectionChanged">
<Columns>
<BoundField DataField="Name" HeaderText="Name" />
<BoundField DataField="Price" HeaderText="Price" DataFormatString="{0:C}" />
</Columns>
<SelectedRowStyle CssClass="selected-row" BackColor="LightBlue" />
</GridView>
@if (SelectedProduct is not null)
{
<p>Selected: @SelectedProduct.Name</p>
}
@code {
private List<Product> Products = new();
private int selectedIndex = -1;
private Product? SelectedProduct => selectedIndex >= 0 && selectedIndex < Products.Count
? Products[selectedIndex]
: null;
private void HandleSelectionChanged(int newIndex)
{
selectedIndex = newIndex;
}
}
Selection with Cancellation
@* Prevent selection of inactive items *@
<GridView DataSource="@Products"
ItemType="Product"
AutoGenerateSelectButton="true"
SelectedIndex="@selectedIndex"
SelectedIndexChanging="HandleSelecting"
SelectedIndexChanged="HandleSelected">
<Columns>
<BoundField DataField="Name" HeaderText="Name" />
<BoundField DataField="IsActive" HeaderText="Active" />
</Columns>
</GridView>
@code {
private List<Product> Products = new();
private int selectedIndex = -1;
private void HandleSelecting(GridViewSelectEventArgs e)
{
// Cancel selection of inactive products
if (!Products[e.NewSelectedIndex].IsActive)
{
e.Cancel = true;
}
}
private void HandleSelected(int newIndex)
{
selectedIndex = newIndex;
}
}
Style Sub-Components
@* GridView with comprehensive styling *@
<GridView DataSource="@Products"
ItemType="Product"
AutoGenerateColumns="true"
ShowHeader="true"
ShowFooter="true"
GridLines="Both"
CellPadding="4"
UseAccessibleHeader="true"
Caption="Product Inventory"
CaptionAlign="Top">
<HeaderStyle CssClass="grid-header" BackColor="DarkBlue" ForeColor="White" />
<RowStyle CssClass="grid-row" BackColor="White" />
<AlternatingRowStyle CssClass="grid-alt-row" BackColor="LightGray" />
<SelectedRowStyle CssClass="grid-selected" BackColor="LightBlue" />
<FooterStyle CssClass="grid-footer" BackColor="DarkBlue" ForeColor="White" />
<EditRowStyle CssClass="grid-edit" BackColor="LightYellow" />
<PagerStyle CssClass="grid-pager" />
</GridView>
Empty Data Template
@* GridView with custom empty data display *@
<GridView DataSource="@FilteredProducts"
ItemType="Product"
AutoGenerateColumns="true"
ShowHeaderWhenEmpty="true"
EmptyDataText="No products found.">
<EmptyDataTemplate>
<div class="empty-message">
<p>No products match your filter criteria.</p>
<Button Text="Clear Filters" OnClick="ClearFilters" />
</div>
</EmptyDataTemplate>
<EmptyDataRowStyle CssClass="empty-row" ForeColor="Gray" />
</GridView>
@code {
private List<Product> FilteredProducts = new();
private void ClearFilters()
{
// Reset filters and reload data
}
}
Selection Properties Reference
| Property | Type | Default | Description |
|---|
GridViewRow Compatibility
BWFC provides full Web Forms GridViewRow compatibility so that migrated code-behind files compile and work with zero changes. This means patterns like CartList.Rows[i].FindControl("PurchaseQuantity") and GetValues(GridViewRow row) work exactly as they did in Web Forms.
Rows Typed Indexer
GridView<T>.Rows returns a GridViewRowCollection<T> whose indexer returns GridViewRow<T> (not IRow<T>):
// This "just works" — Rows[i] returns GridViewRow<T>
for (int i = 0; i < CartList.Rows.Count; i++)
{
GridViewRow<CartItem> row = CartList.Rows[i];
// ...
}
Implicit Conversion to Non-Generic GridViewRow
GridViewRow<T> defines an implicit operator to the non-generic GridViewRow class, so method signatures like GetValues(GridViewRow row) accept GridViewRow<T> instances automatically:
// Web Forms pattern — compiles unchanged in BWFC
private ShoppingCartUpdates GetValues(GridViewRow row)
{
TextBox quantityTextBox = (TextBox)row.FindControl("PurchaseQuantity");
// ...
}
// Called with the typed row — implicit conversion handles it
var updates = GetValues(CartList.Rows[i]);
FindControl on GridViewRow
Both GridViewRow<T> and the non-generic GridViewRow support FindControl(string id). In SSR mode, FindControl returns proxy TextBox and CheckBox instances populated from form POST data, matching the Web Forms pattern where controls inside TemplateField are accessed by ID.
RowState
GridViewRow<T>.RowState returns a DataControlRowState flags enum, matching the Web Forms API:
DataControlRowState.Normal— even-indexed rowsDataControlRowState.Alternate— odd-indexed rowsDataControlRowState.Edit— row in edit modeDataControlRowState.Selected— selected row
Cells and ExtractValuesFromCell
GridViewRow<T>.Cells returns a DataControlFieldCellCollection wrapping the row's columns. Each DataControlFieldCell exposes a ContainingField with an ExtractValuesFromCell method that populates an IOrderedDictionary with the cell's value:
// Web Forms pattern — works unchanged
var dict = new OrderedDictionary();
row.Cells[0].ContainingField.ExtractValuesFromCell(dict, row, DataControlRowState.Normal, true);
string productName = (string)dict["ProductName"];
End-to-End WingtipToys Pattern
The canonical WingtipToys UpdateCartItems() pattern compiles and runs with zero code changes:
public struct ShoppingCartUpdates
{
public int ProductId;
public int PurchaseQuantity;
public bool RemoveItem;
}
private ShoppingCartUpdates GetValues(GridViewRow row)
{
var updates = new ShoppingCartUpdates();
updates.PurchaseQuantity = int.Parse(
((TextBox)row.FindControl("PurchaseQuantity")).Text);
updates.RemoveItem =
((CheckBox)row.FindControl("chkRemove")).Checked;
return updates;
}
protected void UpdateCartItems()
{
for (int i = 0; i < CartList.Rows.Count; i++)
{
var updates = GetValues(CartList.Rows[i]); // implicit operator
// process updates...
}
}
| SelectedIndex | int | -1 | Zero-based index of the selected row. -1 = no selection. |
| SelectedRow | ItemType | default | Read-only. Returns the data item for the selected row. |
| SelectedValue | object | null | Read-only. Returns the DataKeyNames value of the selected row. |
| AutoGenerateSelectButton | bool | false | When true, adds a "Select" link column. |
| SelectedIndexChanging | EventCallback<GridViewSelectEventArgs> | — | Fires before selection changes. Set Cancel = true to prevent. |
| SelectedIndexChanged | EventCallback<int> | — | Fires after the selected row changes. |
Style Sub-Components Reference
All style sub-components use TableItemStyle which supports:
| Property | Type | Description |
|---|---|---|
CssClass | string | CSS class name |
BackColor | WebColor | Background color |
ForeColor | WebColor | Text color |
BorderColor | WebColor | Border color |
BorderStyle | BorderStyle | Border style (Solid, Dashed, etc.) |
BorderWidth | Unit | Border width |
Font | FontInfo | Font settings |
Height | Unit | Row height |
Width | Unit | Row width |
HorizontalAlign | HorizontalAlign | Content alignment |
Wrap | bool | Whether content wraps |
Available style sub-components:
| Component | Applied To |
|---|---|
<RowStyle> | All data rows |
<AlternatingRowStyle> | Even-numbered data rows |
<HeaderStyle> | Header row |
<FooterStyle> | Footer row |
<SelectedRowStyle> | Currently selected row |
<EditRowStyle> | Row being edited |
<EmptyDataRowStyle> | Empty data row |
<PagerStyle> | Pager row |
Display Properties Reference
| Property | Type | Default | Description |
|---|---|---|---|
ShowHeader | bool | true | Show/hide the header row |
ShowFooter | bool | false | Show/hide the footer row |
Caption | string | null | Caption text above the table |
CaptionAlign | TableCaptionAlign | NotSet | Caption alignment (Top, Bottom, Left, Right) |
GridLines | GridLines | None | Table gridlines (None, Horizontal, Vertical, Both) |
UseAccessibleHeader | bool | false | Render <th scope="col"> instead of <td> |
CellPadding | int | -1 | Cell padding in pixels (-1 = not set) |
CellSpacing | int | -1 | Cell spacing in pixels (-1 = not set) |
ShowHeaderWhenEmpty | bool | false | Show column headers when data source is empty |
EmptyDataText | string | null | Text shown when data source is empty |
EmptyDataTemplate | RenderFragment | null | Custom template shown when data source is empty |
See Also
- DataGrid — Legacy grid control
- DataList — For custom layout of repeating data
- Repeater — For lightweight data repetition
- ListView — Full-featured list with CRUD and paging
- DetailsView — Single record display
- FormView — Custom single record layout
- DataPager — Shared paging for multiple controls
- PagerSettings — Shared pager configuration