Skip to content

DetailsView

The DetailsView component emulates the ASP.NET Web Forms asp:DetailsView control. It displays a single record from a data source in a vertical table layout, with one row per field. It supports read-only, edit, and insert modes, paging between records, and auto-generated or explicitly defined fields.

Original Microsoft documentation: https://docs.microsoft.com/en-us/dotnet/api/system.web.ui.webcontrols.detailsview?view=netframework-4.8

Blazor Features Supported

  • Single-record display in a two-column table (label + value per row)
  • AutoGenerateRows — automatically generates rows from the data item's public properties
  • Three display modes via DetailsViewMode enum: ReadOnly, Edit, Insert
  • DefaultMode — sets the initial mode
  • ModeChanging / ModeChanged events
  • AutoGenerateEditButton, AutoGenerateDeleteButton, AutoGenerateInsertButton — command row buttons
  • CRUD events: ItemCommand, ItemDeleting / ItemDeleted, ItemInserting / ItemInserted, ItemUpdating / ItemUpdated
  • Cancellable pre-operation events (ItemDeleting, ItemInserting, ItemUpdating)
  • AllowPaging with numeric pager — navigate between items in the data source
  • PageIndex / PageIndexChanging / PageIndexChanged events
  • DataKeyNames — primary key field identification
  • HeaderText / HeaderTemplate, FooterText / FooterTemplate
  • EmptyDataText / EmptyDataTemplate — displayed when data source is empty
  • PagerTemplate — custom pager UI
  • Fields — explicit field definitions (BoundField, TemplateField)
  • GridLines, CellPadding, CellSpacing — table layout control
  • CssClass — CSS class on the outer table
  • Caption / CaptionAlign — renders a <caption> element for table accessibility
  • Visible — show/hide the entire control
  • Generic ItemType for strongly typed data binding
  • Style sub-components (RowStyle, AlternatingRowStyle, HeaderStyle, FooterStyle, CommandRowStyle, EditRowStyle, InsertRowStyle, FieldHeaderStyle, EmptyDataRowStyle, PagerStyle)
  • PagerSettings — configurable pager button modes, text, images, and position

Blazor Notes

  • The component is generic: DetailsView<ItemType>. You must specify ItemType when using it.
  • Field definitions are added as child content inside a <Fields> block. They register themselves with the parent via a CascadingValue.
  • When AutoGenerateRows="true" (the default) and no explicit fields are defined, the component reflects over ItemType to generate rows for each public readable property.
  • The pager displays one page number per item in the data source (each "page" is one record).

Web Forms Features NOT Supported

  • DataSourceID — Blazor does not use server-side data source controls; bind data directly via Items
  • SortingAllowSorting is not implemented
  • CommandField / ButtonField columns — Use AutoGenerateEditButton / AutoGenerateDeleteButton / AutoGenerateInsertButton or custom templates
  • ViewState — Not needed; Blazor preserves component state natively
  • Theming / SkinID — Not applicable to Blazor

Web Forms Declarative Syntax

<asp:DetailsView
    AllowPaging="True|False"
    AutoGenerateDeleteButton="True|False"
    AutoGenerateEditButton="True|False"
    AutoGenerateInsertButton="True|False"
    AutoGenerateRows="True|False"
    Caption="string"
    CaptionAlign="NotSet|Top|Bottom|Left|Right"
    CellPadding="integer"
    CellSpacing="integer"
    CssClass="string"
    DataKeyNames="string"
    DataSourceID="string"
    DefaultMode="ReadOnly|Edit|Insert"
    EmptyDataText="string"
    GridLines="None|Horizontal|Vertical|Both"
    HeaderText="string"
    FooterText="string"
    ID="string"
    OnItemCommand="ItemCommand event handler"
    OnItemDeleted="ItemDeleted event handler"
    OnItemDeleting="ItemDeleting event handler"
    OnItemInserted="ItemInserted event handler"
    OnItemInserting="ItemInserting event handler"
    OnItemUpdated="ItemUpdated event handler"
    OnItemUpdating="ItemUpdating event handler"
    OnModeChanged="ModeChanged event handler"
    OnModeChanging="ModeChanging event handler"
    OnPageIndexChanged="PageIndexChanged event handler"
    OnPageIndexChanging="PageIndexChanging event handler"
    PageIndex="integer"
    Visible="True|False"
    runat="server"
>
    <AlternatingRowStyle />
    <CommandRowStyle />
    <EditRowStyle />
    <EmptyDataRowStyle />
    <FieldHeaderStyle />
    <FooterStyle />
    <HeaderStyle />
    <InsertRowStyle />
    <PagerSettings
        Mode="NextPrevious|Numeric|NextPreviousFirstLast|NumericFirstLast"
        FirstPageText="string"
        LastPageText="string"
        NextPageText="string"
        PreviousPageText="string"
        PageButtonCount="integer"
        Position="Bottom|Top|TopAndBottom"
        Visible="True|False"
    />
    <PagerStyle />
    <RowStyle />
    <Fields>
        <asp:BoundField DataField="string" HeaderText="string" ReadOnly="True|False" />
        <asp:TemplateField HeaderText="string">
            <ItemTemplate><!-- child controls --></ItemTemplate>
            <EditItemTemplate><!-- child controls --></EditItemTemplate>
        </asp:TemplateField>
    </Fields>
    <HeaderTemplate><!-- child controls --></HeaderTemplate>
    <FooterTemplate><!-- child controls --></FooterTemplate>
    <EmptyDataTemplate><!-- child controls --></EmptyDataTemplate>
    <PagerTemplate><!-- child controls --></PagerTemplate>
</asp:DetailsView>

Blazor Syntax

<DetailsView ItemType="Product"
    Items="@Products"
    AutoGenerateRows="true"
    AllowPaging="true"
    AutoGenerateEditButton="true"
    AutoGenerateDeleteButton="true"
    DefaultMode="DetailsViewMode.ReadOnly"
    HeaderText="Product Details"
    EmptyDataText="No products found."
    Caption="Product Record"
    CaptionAlign="TableCaptionAlign.Top"
    CssClass="details-grid"
    GridLines="GridLines.Both"
    ItemDeleting="HandleDeleting"
    ItemUpdating="HandleUpdating"
    ModeChanging="HandleModeChanging"
    PageIndexChanging="HandlePageChanging">
    <PagerSettings Mode="PagerButtons.NumericFirstLast"
                   FirstPageText="First"
                   LastPageText="Last"
                   Position="PagerPosition.Bottom" />
    <RowStyle BackColor="#FFFFFF" />
    <AlternatingRowStyle BackColor="#F7F7F7" />
    <HeaderStyle BackColor="#336699" ForeColor="#FFFFFF" Font-Bold="true" />
    <FooterStyle BackColor="#CCCCCC" />
    <CommandRowStyle BackColor="#EEEEEE" />
    <FieldHeaderStyle Font-Bold="true" />
    <PagerStyle BackColor="#DDDDDD" HorizontalAlign="HorizontalAlign.Center" />
</DetailsView>

@code {
    private List<Product> Products = new();

    private void HandleDeleting(DetailsViewDeleteEventArgs e)
    {
        // e.RowIndex gives you the current page index
        // Perform delete logic; set e.Cancel = true to abort
    }

    private void HandleUpdating(DetailsViewUpdateEventArgs e)
    {
        // Perform update logic; set e.Cancel = true to abort
    }

    private void HandleModeChanging(DetailsViewModeEventArgs e)
    {
        // e.NewMode tells you the target mode
        // e.CancelingEdit tells you if this is a cancel operation
    }

    private void HandlePageChanging(PageChangedEventArgs e)
    {
        // e.NewPageIndex gives you the target page
    }
}

With Explicit Fields

<DetailsView ItemType="Product"
    Items="@Products"
    AutoGenerateRows="false"
    AllowPaging="true">
    <Fields>
        <BoundField DataField="Name" HeaderText="Product Name" />
        <BoundField DataField="Price" HeaderText="Unit Price" />
        <TemplateField HeaderText="Actions">
            <ItemTemplate>
                <a href="/products/@context.Id">View</a>
            </ItemTemplate>
        </TemplateField>
    </Fields>
</DetailsView>

With Custom Templates

<DetailsView ItemType="Product"
    Items="@Products"
    AutoGenerateRows="true">
    <HeaderTemplate>
        <strong>Product Information</strong>
    </HeaderTemplate>
    <EmptyDataTemplate>
        <p>No products available. <a href="/products/new">Add one</a>.</p>
    </EmptyDataTemplate>
    <FooterTemplate>
        <em>Last updated: @DateTime.Now.ToShortDateString()</em>
    </FooterTemplate>
</DetailsView>

HTML Output

The component renders a table with one row per field, matching the Web Forms DetailsView output:

<table cellspacing="0" rules="all" border="1"
       style="border-collapse:collapse" class="details-grid">
  <!-- Header Row -->
  <tr>
    <td colspan="2">Product Details</td>
  </tr>
  <!-- Field Rows (one per property or defined field) -->
  <tr>
    <td>Id</td>
    <td>1</td>
  </tr>
  <tr>
    <td>Name</td>
    <td>Widget</td>
  </tr>
  <tr>
    <td>Price</td>
    <td>9.99</td>
  </tr>
  <!-- Command Row (when edit/delete/insert buttons enabled) -->
  <tr>
    <td colspan="2">
      <a href="javascript:void(0);">Edit</a>&nbsp;
      <a href="javascript:void(0);">Delete</a>
    </td>
  </tr>
  <!-- Pager Row (when AllowPaging and multiple items) -->
  <tr>
    <td colspan="2">
      <table>
        <tr>
          <td><span>1</span></td>
          <td><a href="javascript:void(0);">2</a></td>
          <td><a href="javascript:void(0);">3</a></td>
        </tr>
      </table>
    </td>
  </tr>
  <!-- Footer Row -->
  <tr>
    <td colspan="2">Footer text here</td>
  </tr>
</table>

In Edit or Insert mode, the command row changes to show Update/Cancel or Insert/Cancel links:

<!-- Edit mode command row -->
<tr>
  <td colspan="2">
    <a href="javascript:void(0);">Update</a>&nbsp;
    <a href="javascript:void(0);">Cancel</a>
  </td>
</tr>

Style Sub-Components

The DetailsView supports style sub-components that control the appearance of different row types. Each is specified as a child element:

Style Component Description
RowStyle Styles normal data rows
AlternatingRowStyle Styles alternating data rows
HeaderStyle Styles the header row
FooterStyle Styles the footer row
CommandRowStyle Styles the command row (Edit/Delete/Insert buttons)
EditRowStyle Styles rows in Edit mode
InsertRowStyle Styles rows in Insert mode
FieldHeaderStyle Styles the field label cells (left column)
EmptyDataRowStyle Styles the empty data row
PagerStyle Styles the pager row

Each style component accepts standard style properties: BackColor, ForeColor, CssClass, Font-Bold, Font-Italic, Font-Size, HorizontalAlign, VerticalAlign, Width, Height, etc.

Caption Property

The Caption and CaptionAlign properties render a <caption> element inside the <table>, providing an accessible description of the table's purpose:

<DetailsView ItemType="Product" Items="@Products"
    Caption="Product Details"
    CaptionAlign="TableCaptionAlign.Top" />
CaptionAlign Value Effect
NotSet Default browser positioning
Top Caption above the table
Bottom Caption below the table
Left Caption text left-aligned
Right Caption text right-aligned

Migration Notes

  1. Remove asp: prefix — Change <asp:DetailsView> to <DetailsView>
  2. Remove runat="server" — Not needed in Blazor
  3. Add ItemType — The Blazor component is generic; specify ItemType="YourClass"
  4. Replace DataSourceID — Use Items="@yourCollection" instead of binding to a server-side DataSource control
  5. Field declarations — Remove asp: prefix from <asp:BoundField> and <asp:TemplateField>; place them inside <Fields> block
  6. Event signatures — Events use typed EventArgs classes (DetailsViewDeleteEventArgs, DetailsViewUpdateEventArgs, etc.)
  7. Styles — Web Forms <HeaderStyle>, <RowStyle>, etc. work as child elements in Blazor with the same property names (BackColor, ForeColor, Font-Bold, etc.)
  8. PagerSettings — Configure via child <PagerSettings> element instead of dash-separated attributes. See PagerSettings for details.

Before (Web Forms)

<asp:DetailsView ID="dvProduct"
    DataSourceID="SqlDataSource1"
    AutoGenerateRows="True"
    AllowPaging="True"
    AutoGenerateEditButton="True"
    OnItemUpdating="dvProduct_ItemUpdating"
    runat="server">
    <HeaderStyle BackColor="#336699" ForeColor="White" />
</asp:DetailsView>

After (Blazor)

<DetailsView ItemType="Product"
    Items="@Products"
    AutoGenerateRows="true"
    AllowPaging="true"
    AutoGenerateEditButton="true"
    CssClass="product-details"
    ItemUpdating="HandleUpdating">
    <HeaderStyle BackColor="#336699" ForeColor="#FFFFFF" />
</DetailsView>

@code {
    private List<Product> Products = new();

    protected override async Task OnInitializedAsync()
    {
        Products = await ProductService.GetAllAsync();
    }

    private void HandleUpdating(DetailsViewUpdateEventArgs e)
    {
        // Perform update
    }
}

See Also

  • FormView — Similar single-record view with full template control
  • GridView — Multi-record tabular display with similar field types
  • DataList — Repeating data display
  • PagerSettings — Shared pager configuration