ASP.NET 的 DetailsView 控件是一個強大的數據展示與編輯工具,專門用於以表單形式呈現單筆記錄,並內建支援新增、編輯、刪除等操作。不同於 GridView 的表格式列表,DetailsView 更適合「主從式」介面或單筆資料的詳細維護。本文將透過完整的 ASPX 與 C# 代碼範例,詳細解析 DetailsView 的核心屬性、模板欄位設計、事件處理機制,以及實際專案中常見的資料繫結與 CRUD 實作技巧。
DetailsView 的靈活性在於 <Fields> 區塊中自訂的 TemplateField。每個欄位可分別定義 ItemTemplate(唯讀)、EditItemTemplate(編輯)、InsertItemTemplate(新增)三種狀態的顯示內容,從而精確控制使用者介面。
<asp:DetailsView ID="DetailsView1" runat="server"
AutoGenerateRows="False"
Height="50px" Width="500px"
OnModeChanging="DetailsView1_ModeChanging"
OnItemDeleting="DetailsView1_ItemDeleting"
OnItemUpdating="DetailsView1_ItemUpdating"
OnItemInserting="DetailsView1_ItemInserting">
<Fields>
<!-- 欄位定義 -->
</Fields>
</asp:DetailsView>
ModeChanging(模式切換)、ItemDeleting(刪除)、ItemUpdating(更新)、ItemInserting(新增),分別對應 CRUD 操作的觸發點。以「Title」欄位為例,展示三種模板的寫法差異:
<asp:TemplateField HeaderText="Title">
<!-- 唯讀模式:直接輸出資料 -->
<ItemTemplate>
<%# Eval("Title") %>
</ItemTemplate>
<!-- 新增模式:提供空白輸入框 -->
<InsertItemTemplate>
<asp:TextBox ID="txtInsertTitle" Text="InsertTitle" runat="server" />
</InsertItemTemplate>
<!-- 編輯模式:回填原值供修改 -->
<EditItemTemplate>
<asp:TextBox ID="txtEditTitle" Text='<%# Eval("Title") %>' runat="server" />
</EditItemTemplate>
</asp:TemplateField>
關鍵細節:編輯模式的 TextBox 必須使用單引號包裹 Text='<%# Eval("Title") %>',避免雙引號衝突導致編譯錯誤。
透過 CommandName 屬性指定內建命令(Edit、New、Delete、Insert、Update、Cancel),DetailsView 會自動識別並觸發對應事件:
<asp:TemplateField HeaderText="操作">
<ItemTemplate>
<asp:Button CommandName="Edit" Text="編輯" CausesValidation="False" />
<asp:Button CommandName="New" Text="新建" CausesValidation="False" />
<asp:Button CommandName="Delete" Text="刪除"
OnClientClick="return confirm('確定要刪除此筆資料嗎?');" CausesValidation="False" />
</ItemTemplate>
<InsertItemTemplate>
<asp:Button CommandName="Insert" Text="插入" CausesValidation="True" />
<asp:Button CommandName="Cancel" Text="取消" CausesValidation="False" />
</InsertItemTemplate>
<EditItemTemplate>
<asp:Button CommandName="Update" Text="更新" CausesValidation="True"
OnClientClick="return confirm('確定要更新資料嗎?');" />
<asp:Button CommandName="Cancel" Text="取消" CausesValidation="False" />
</EditItemTemplate>
</asp:TemplateField>
最佳實踐:刪除與更新等不可逆操作,務必加上 OnClientClick 確認對話框,降低誤操作風險。
public class Log
{
public int Id { get; set; }
public string Title { get; set; }
public string LogContext { get; set; }
}
private void DataToBind()
{
this.DetailsView1.DataSource = GetLogData();
this.DetailsView1.DataBind();
}
private List<Log> GetLogData()
{
var logs = new List<Log>();
for (int i = 1; i <= 10; i++)
{
logs.Add(new Log { Id = i, Title = "標題" + i, LogContext = "內容" + i });
}
return logs;
}
實務上可替換為真實資料庫查詢(如 Entity Framework、Dapper 或 ADO.NET)。
protected void DetailsView1_ModeChanging(object sender, DetailsViewModeEventArgs e)
{
this.DetailsView1.ChangeMode(e.NewMode);
DataToBind(); // 切換模式後必須重新繫結
}
protected void DetailsView1_ItemDeleting(object sender, DetailsViewDeleteEventArgs e)
{
// 實務:根據 e.Keys["Id"] 執行資料庫刪除
// 此處僅示範
Response.Write("刪除操作 - ID: " + e.Keys["Id"]);
// 執行完畢後通常需重新繫結回 ReadOnly 模式
this.DetailsView1.ChangeMode(DetailsViewMode.ReadOnly);
DataToBind();
}
protected void DetailsView1_ItemUpdating(object sender, DetailsViewUpdateEventArgs e)
{
// 透過 FindControl 取得編輯模式下的 TextBox 控件
TextBox tbTitle = (TextBox)this.DetailsView1.FindControl("txtEditTitle");
TextBox tbContext = (TextBox)this.DetailsView1.FindControl("txtEditLogContext");
string newTitle = tbTitle?.Text;
string newContext = tbContext?.Text;
int id = Convert.ToInt32(e.Keys["Id"]);
// 實務:執行資料庫 UPDATE
Response.Write($"更新操作 - ID:{id}, Title:{newTitle}, Context:{newContext}");
this.DetailsView1.ChangeMode(DetailsViewMode.ReadOnly);
DataToBind();
}
注意:原始範例中 FindControl("txtEditTitle") 被重複使用導致 Bug,正確應分別對應 txtEditTitle 與 txtEditLogContext。
protected void DetailsView1_ItemInserting(object sender, DetailsViewInsertEventArgs e)
{
TextBox tbTitle = (TextBox)this.DetailsView1.FindControl("txtInsertTitle");
TextBox tbContext = (TextBox)this.DetailsView1.FindControl("txtInsertLogContext");
// 實務:執行資料庫 INSERT
Response.Write($"新增操作 - Title:{tbTitle?.Text}, Context:{tbContext?.Text}");
this.DetailsView1.ChangeMode(DetailsViewMode.ReadOnly);
DataToBind();
}
Eval("Id"),不提供 TextBox,防止主鍵被竄改。CausesValidation="True",搭配 Validator 控件實現伺服器端/用戶端雙重驗證。Page_Load 僅在 !IsPostBack 時繫結;模式切換、CRUD 完成後均需手動呼叫 DataToBind() 刷新畫面。try-catch,並透過 DetailsView1.Rows[e.RowIndex].Cells[0].Controls 等方式在畫面顯示友善錯誤訊息。DetailsView 控件憑藉聲明式模板與內建命令架構,讓單筆資料的 CRUD 開發變得結構化、可維護。掌握「三種模板對應三種狀態」、「CommandName 自動路由事件」、「FindControl 取值」三大核心概念,即可靈活應對大多數主從頁面或資料維護需求。實務專案中,建議搭配資料存取層(DAL)與驗證層,進一步分離關注點,打造健壯的企業級應用。