The GridView component is meant to emulate the asp:GridView control in markup and is defined in the System.Web.UI.WebControls.GridView class
- 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)
- 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.
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>
```
@* 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;
}
}@* 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;
}
}@* 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;
}
}@* 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;
}
}@* 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;
}
}@* 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;
}
}@* 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>@* 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
}
}| Property | Type | Default | Description |
|---|
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.
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];
// ...
}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]);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.
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
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"];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. |
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 |
| 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 |
- 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