|
| 1 | +# DetailsView |
| 2 | + |
| 3 | +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. |
| 4 | + |
| 5 | +Original Microsoft documentation: https://docs.microsoft.com/en-us/dotnet/api/system.web.ui.webcontrols.detailsview?view=netframework-4.8 |
| 6 | + |
| 7 | +## Blazor Features Supported |
| 8 | + |
| 9 | +- Single-record display in a two-column table (label + value per row) |
| 10 | +- `AutoGenerateRows` — automatically generates rows from the data item's public properties |
| 11 | +- Three display modes via `DetailsViewMode` enum: `ReadOnly`, `Edit`, `Insert` |
| 12 | +- `DefaultMode` — sets the initial mode |
| 13 | +- `ModeChanging` / `ModeChanged` events |
| 14 | +- `AutoGenerateEditButton`, `AutoGenerateDeleteButton`, `AutoGenerateInsertButton` — command row buttons |
| 15 | +- CRUD events: `ItemCommand`, `ItemDeleting` / `ItemDeleted`, `ItemInserting` / `ItemInserted`, `ItemUpdating` / `ItemUpdated` |
| 16 | +- Cancellable pre-operation events (`ItemDeleting`, `ItemInserting`, `ItemUpdating`) |
| 17 | +- `AllowPaging` with numeric pager — navigate between items in the data source |
| 18 | +- `PageIndex` / `PageIndexChanging` / `PageIndexChanged` events |
| 19 | +- `DataKeyNames` — primary key field identification |
| 20 | +- `HeaderText` / `HeaderTemplate`, `FooterText` / `FooterTemplate` |
| 21 | +- `EmptyDataText` / `EmptyDataTemplate` — displayed when data source is empty |
| 22 | +- `PagerTemplate` — custom pager UI |
| 23 | +- `Fields` — explicit field definitions (BoundField, TemplateField) |
| 24 | +- `GridLines`, `CellPadding`, `CellSpacing` — table layout control |
| 25 | +- `CssClass` — CSS class on the outer table |
| 26 | +- `Visible` — show/hide the entire control |
| 27 | +- Generic `ItemType` for strongly typed data binding |
| 28 | + |
| 29 | +### Blazor Notes |
| 30 | + |
| 31 | +- The component is generic: `DetailsView<ItemType>`. You must specify `ItemType` when using it. |
| 32 | +- Field definitions are added as child content inside a `<Fields>` block. They register themselves with the parent via a `CascadingValue`. |
| 33 | +- When `AutoGenerateRows="true"` (the default) and no explicit fields are defined, the component reflects over `ItemType` to generate rows for each public readable property. |
| 34 | +- The pager displays one page number per item in the data source (each "page" is one record). |
| 35 | + |
| 36 | +## Web Forms Features NOT Supported |
| 37 | + |
| 38 | +- **DataSourceID** — Blazor does not use server-side data source controls; bind data directly via `Items` |
| 39 | +- **Sorting** — `AllowSorting` is not implemented |
| 40 | +- **PagerSettings** — Only numeric paging or custom `PagerTemplate`; `PagerSettings` sub-properties (NextPrevious, FirstLast modes) are not supported |
| 41 | +- **Row styles** (HeaderStyle, RowStyle, AlternatingRowStyle, EditRowStyle, etc.) — Use CSS classes instead |
| 42 | +- **CommandField / ButtonField** columns — Use `AutoGenerateEditButton` / `AutoGenerateDeleteButton` / `AutoGenerateInsertButton` or custom templates |
| 43 | +- **ViewState** — Not needed; Blazor preserves component state natively |
| 44 | +- **Theming / SkinID** — Not applicable to Blazor |
| 45 | + |
| 46 | +## Web Forms Declarative Syntax |
| 47 | + |
| 48 | +```html |
| 49 | +<asp:DetailsView |
| 50 | + AllowPaging="True|False" |
| 51 | + AutoGenerateDeleteButton="True|False" |
| 52 | + AutoGenerateEditButton="True|False" |
| 53 | + AutoGenerateInsertButton="True|False" |
| 54 | + AutoGenerateRows="True|False" |
| 55 | + CellPadding="integer" |
| 56 | + CellSpacing="integer" |
| 57 | + CssClass="string" |
| 58 | + DataKeyNames="string" |
| 59 | + DataSourceID="string" |
| 60 | + DefaultMode="ReadOnly|Edit|Insert" |
| 61 | + EmptyDataText="string" |
| 62 | + GridLines="None|Horizontal|Vertical|Both" |
| 63 | + HeaderText="string" |
| 64 | + FooterText="string" |
| 65 | + ID="string" |
| 66 | + OnItemCommand="ItemCommand event handler" |
| 67 | + OnItemDeleted="ItemDeleted event handler" |
| 68 | + OnItemDeleting="ItemDeleting event handler" |
| 69 | + OnItemInserted="ItemInserted event handler" |
| 70 | + OnItemInserting="ItemInserting event handler" |
| 71 | + OnItemUpdated="ItemUpdated event handler" |
| 72 | + OnItemUpdating="ItemUpdating event handler" |
| 73 | + OnModeChanged="ModeChanged event handler" |
| 74 | + OnModeChanging="ModeChanging event handler" |
| 75 | + OnPageIndexChanged="PageIndexChanged event handler" |
| 76 | + OnPageIndexChanging="PageIndexChanging event handler" |
| 77 | + PageIndex="integer" |
| 78 | + Visible="True|False" |
| 79 | + runat="server" |
| 80 | +> |
| 81 | + <Fields> |
| 82 | + <asp:BoundField DataField="string" HeaderText="string" ReadOnly="True|False" /> |
| 83 | + <asp:TemplateField HeaderText="string"> |
| 84 | + <ItemTemplate><!-- child controls --></ItemTemplate> |
| 85 | + <EditItemTemplate><!-- child controls --></EditItemTemplate> |
| 86 | + </asp:TemplateField> |
| 87 | + </Fields> |
| 88 | + <HeaderTemplate><!-- child controls --></HeaderTemplate> |
| 89 | + <FooterTemplate><!-- child controls --></FooterTemplate> |
| 90 | + <EmptyDataTemplate><!-- child controls --></EmptyDataTemplate> |
| 91 | + <PagerTemplate><!-- child controls --></PagerTemplate> |
| 92 | +</asp:DetailsView> |
| 93 | +``` |
| 94 | + |
| 95 | +## Blazor Syntax |
| 96 | + |
| 97 | +```razor |
| 98 | +<DetailsView ItemType="Product" |
| 99 | + Items="@Products" |
| 100 | + AutoGenerateRows="true" |
| 101 | + AllowPaging="true" |
| 102 | + AutoGenerateEditButton="true" |
| 103 | + AutoGenerateDeleteButton="true" |
| 104 | + DefaultMode="DetailsViewMode.ReadOnly" |
| 105 | + HeaderText="Product Details" |
| 106 | + EmptyDataText="No products found." |
| 107 | + CssClass="details-grid" |
| 108 | + GridLines="GridLines.Both" |
| 109 | + ItemDeleting="HandleDeleting" |
| 110 | + ItemUpdating="HandleUpdating" |
| 111 | + ModeChanging="HandleModeChanging" |
| 112 | + PageIndexChanging="HandlePageChanging" /> |
| 113 | +
|
| 114 | +@code { |
| 115 | + private List<Product> Products = new(); |
| 116 | +
|
| 117 | + private void HandleDeleting(DetailsViewDeleteEventArgs e) |
| 118 | + { |
| 119 | + // e.RowIndex gives you the current page index |
| 120 | + // Perform delete logic; set e.Cancel = true to abort |
| 121 | + } |
| 122 | +
|
| 123 | + private void HandleUpdating(DetailsViewUpdateEventArgs e) |
| 124 | + { |
| 125 | + // Perform update logic; set e.Cancel = true to abort |
| 126 | + } |
| 127 | +
|
| 128 | + private void HandleModeChanging(DetailsViewModeEventArgs e) |
| 129 | + { |
| 130 | + // e.NewMode tells you the target mode |
| 131 | + // e.CancelingEdit tells you if this is a cancel operation |
| 132 | + } |
| 133 | +
|
| 134 | + private void HandlePageChanging(PageChangedEventArgs e) |
| 135 | + { |
| 136 | + // e.NewPageIndex gives you the target page |
| 137 | + } |
| 138 | +} |
| 139 | +``` |
| 140 | + |
| 141 | +### With Explicit Fields |
| 142 | + |
| 143 | +```razor |
| 144 | +<DetailsView ItemType="Product" |
| 145 | + Items="@Products" |
| 146 | + AutoGenerateRows="false" |
| 147 | + AllowPaging="true"> |
| 148 | + <Fields> |
| 149 | + <BoundField DataField="Name" HeaderText="Product Name" /> |
| 150 | + <BoundField DataField="Price" HeaderText="Unit Price" /> |
| 151 | + <TemplateField HeaderText="Actions"> |
| 152 | + <ItemTemplate> |
| 153 | + <a href="/products/@context.Id">View</a> |
| 154 | + </ItemTemplate> |
| 155 | + </TemplateField> |
| 156 | + </Fields> |
| 157 | +</DetailsView> |
| 158 | +``` |
| 159 | + |
| 160 | +### With Custom Templates |
| 161 | + |
| 162 | +```razor |
| 163 | +<DetailsView ItemType="Product" |
| 164 | + Items="@Products" |
| 165 | + AutoGenerateRows="true"> |
| 166 | + <HeaderTemplate> |
| 167 | + <strong>Product Information</strong> |
| 168 | + </HeaderTemplate> |
| 169 | + <EmptyDataTemplate> |
| 170 | + <p>No products available. <a href="/products/new">Add one</a>.</p> |
| 171 | + </EmptyDataTemplate> |
| 172 | + <FooterTemplate> |
| 173 | + <em>Last updated: @DateTime.Now.ToShortDateString()</em> |
| 174 | + </FooterTemplate> |
| 175 | +</DetailsView> |
| 176 | +``` |
| 177 | + |
| 178 | +## HTML Output |
| 179 | + |
| 180 | +The component renders a table with one row per field, matching the Web Forms DetailsView output: |
| 181 | + |
| 182 | +```html |
| 183 | +<table cellspacing="0" rules="all" border="1" |
| 184 | + style="border-collapse:collapse" class="details-grid"> |
| 185 | + <!-- Header Row --> |
| 186 | + <tr> |
| 187 | + <td colspan="2">Product Details</td> |
| 188 | + </tr> |
| 189 | + <!-- Field Rows (one per property or defined field) --> |
| 190 | + <tr> |
| 191 | + <td>Id</td> |
| 192 | + <td>1</td> |
| 193 | + </tr> |
| 194 | + <tr> |
| 195 | + <td>Name</td> |
| 196 | + <td>Widget</td> |
| 197 | + </tr> |
| 198 | + <tr> |
| 199 | + <td>Price</td> |
| 200 | + <td>9.99</td> |
| 201 | + </tr> |
| 202 | + <!-- Command Row (when edit/delete/insert buttons enabled) --> |
| 203 | + <tr> |
| 204 | + <td colspan="2"> |
| 205 | + <a href="javascript:void(0);">Edit</a> |
| 206 | + <a href="javascript:void(0);">Delete</a> |
| 207 | + </td> |
| 208 | + </tr> |
| 209 | + <!-- Pager Row (when AllowPaging and multiple items) --> |
| 210 | + <tr> |
| 211 | + <td colspan="2"> |
| 212 | + <table> |
| 213 | + <tr> |
| 214 | + <td><span>1</span></td> |
| 215 | + <td><a href="javascript:void(0);">2</a></td> |
| 216 | + <td><a href="javascript:void(0);">3</a></td> |
| 217 | + </tr> |
| 218 | + </table> |
| 219 | + </td> |
| 220 | + </tr> |
| 221 | + <!-- Footer Row --> |
| 222 | + <tr> |
| 223 | + <td colspan="2">Footer text here</td> |
| 224 | + </tr> |
| 225 | +</table> |
| 226 | +``` |
| 227 | + |
| 228 | +In **Edit** or **Insert** mode, the command row changes to show Update/Cancel or Insert/Cancel links: |
| 229 | + |
| 230 | +```html |
| 231 | +<!-- Edit mode command row --> |
| 232 | +<tr> |
| 233 | + <td colspan="2"> |
| 234 | + <a href="javascript:void(0);">Update</a> |
| 235 | + <a href="javascript:void(0);">Cancel</a> |
| 236 | + </td> |
| 237 | +</tr> |
| 238 | +``` |
| 239 | + |
| 240 | +## Migration Notes |
| 241 | + |
| 242 | +1. **Remove `asp:` prefix** — Change `<asp:DetailsView>` to `<DetailsView>` |
| 243 | +2. **Remove `runat="server"`** — Not needed in Blazor |
| 244 | +3. **Add `ItemType`** — The Blazor component is generic; specify `ItemType="YourClass"` |
| 245 | +4. **Replace `DataSourceID`** — Use `Items="@yourCollection"` instead of binding to a server-side DataSource control |
| 246 | +5. **Field declarations** — Remove `asp:` prefix from `<asp:BoundField>` and `<asp:TemplateField>`; place them inside `<Fields>` block |
| 247 | +6. **Event signatures** — Events use typed `EventArgs` classes (`DetailsViewDeleteEventArgs`, `DetailsViewUpdateEventArgs`, etc.) |
| 248 | +7. **Styles** — Replace `<HeaderStyle>`, `<RowStyle>`, etc. with CSS classes via `CssClass` |
| 249 | + |
| 250 | +### Before (Web Forms) |
| 251 | + |
| 252 | +```html |
| 253 | +<asp:DetailsView ID="dvProduct" |
| 254 | + DataSourceID="SqlDataSource1" |
| 255 | + AutoGenerateRows="True" |
| 256 | + AllowPaging="True" |
| 257 | + AutoGenerateEditButton="True" |
| 258 | + OnItemUpdating="dvProduct_ItemUpdating" |
| 259 | + runat="server"> |
| 260 | + <HeaderStyle BackColor="#336699" ForeColor="White" /> |
| 261 | +</asp:DetailsView> |
| 262 | +``` |
| 263 | + |
| 264 | +### After (Blazor) |
| 265 | + |
| 266 | +```razor |
| 267 | +<DetailsView ItemType="Product" |
| 268 | + Items="@Products" |
| 269 | + AutoGenerateRows="true" |
| 270 | + AllowPaging="true" |
| 271 | + AutoGenerateEditButton="true" |
| 272 | + CssClass="product-details" |
| 273 | + ItemUpdating="HandleUpdating" /> |
| 274 | +
|
| 275 | +@code { |
| 276 | + private List<Product> Products = new(); |
| 277 | +
|
| 278 | + protected override async Task OnInitializedAsync() |
| 279 | + { |
| 280 | + Products = await ProductService.GetAllAsync(); |
| 281 | + } |
| 282 | +
|
| 283 | + private void HandleUpdating(DetailsViewUpdateEventArgs e) |
| 284 | + { |
| 285 | + // Perform update |
| 286 | + } |
| 287 | +} |
| 288 | +``` |
| 289 | + |
| 290 | +## See Also |
| 291 | + |
| 292 | +- [FormView](FormView.md) — Similar single-record view with full template control |
| 293 | +- [GridView](GridView.md) — Multi-record tabular display with similar field types |
| 294 | +- [DataList](DataList.md) — Repeating data display |
0 commit comments