在 ASP.NET WebForms 中,GridView 的 TemplateField 內嵌 DropDownList 時,編輯/查看模式下保持選中值是常見需求。關鍵在於 RowDataBound 事件階段,通過數據項綁定值精準設置 SelectedValue。本文提供完整實現代碼、常見陷阱與最佳實踐。
GridView 綁定數據源(如問題工單列表)DropDownList ddlProVar(問題分類:硬件/軟件/網絡/其他)ProVarState 存儲分類代碼/名稱
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
OnRowDataBound="GridView1_RowDataBound" DataKeyNames="Id">
<Columns>
<asp:BoundField DataField="Title" HeaderText="標題" />
<asp:TemplateField HeaderText="問題分類">
<ItemTemplate>
<asp:DropDownList ID="ddlProVar" runat="server" Enabled="false">
<asp:ListItem Text="硬件" Value="HW" />
<asp:ListItem Text="軟件" Value="SW" />
<asp:ListItem Text="網絡" Value="NW" />
<asp:ListItem Text="其他" Value="OT" />
</asp:DropDownList>
<!-- 隱藏域存儲數據源原始值,避免綁定上下文丟失 -->
<asp:HiddenField ID="hdProVarState" runat="server" Value='<%# Eval("ProVarState") %>' />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e) {
// 僅處理數據行
if (e.Row.RowType != DataControlRowType.DataRow) return;
// 1. 獲取當前行的 DropDownList 與隱藏域
var ddl = e.Row.FindControl("ddlProVar") as DropDownList;
var hd = e.Row.FindControl("hdProVarState") as HiddenField;
if (ddl == null || hd == null) return;
// 2. 獲取數據源綁定的原始值
string boundValue = hd.Value; // 如 "SW"
// 3. 設置選中項(按 Value 匹配,推薦)
SetSelectedByValue(ddl, boundValue);
// 可選:鼠標懸停行高亮
e.Row.Attributes["onmouseover"] = "this.style.backgroundColor='#FFFFCC';";
e.Row.Attributes["onmouseout"] = "this.style.backgroundColor='';";
e.Row.Style["cursor"] = "pointer";
}
///
/// 通用輔助方法:按 Value 設置 DropDownList/ListBox 選中項
///
private void SetSelectedByValue(ListControl list, string value) {
if (string.IsNullOrEmpty(value)) return;
// 清除舊選中
foreach (ListItem item in list.Items) {
item.Selected = false;
}
// 查找並設置新選中
var target = list.Items.FindByValue(value);
if (target != null) {
target.Selected = true;
} else {
// 可選:值不在列表中時的降級處理(如添加「未知」項、記錄日誌)
System.Diagnostics.Debug.WriteLine($"[WARN] DropDownList 未找到值: {value}");
}
}
| 技術點 | 說明 |
|---|---|
RowDataBound 事件 | 每行綁定數據後觸發,此時 e.Row.DataItem 可用,控件已創建,是操作模板列控件的最佳時機 |
FindControl | 在命名容器 (GridViewRow) 中查找控件,必須轉型 |
隱藏域 HiddenField | 在 ItemTemplate 中用 Eval("ProVarState") 綁定原始值,避免在 RowDataBound 中解析 DataItem 類型轉換麻煩 |
ListControl.Items.FindByValue | 比遍歷 foreach 更簡潔高效,直接按 Value 屬性匹配 |
Enabled="false" | 僅查看模式時禁用編輯;編輯模式移除或設置 true |
int,下拉框 Value="1" (string)。Eval("ProVarState", "{0}") 強制 ToString。FindByValue 區分大小寫。SetSelectedByValue 中添加降級邏輯:插入「已棄用:原值」項並選中,或標紅提示。GridView 在 UpdatePanel 內,或回發後重新綁定並觸發 RowDataBound。EditItemTemplate + Bind("ProVarState") 實現自動雙向綁定,無需手動 RowDataBound。
<asp:TemplateField HeaderText="問題分類">
<ItemTemplate>
<asp:Label ID="lblProVar" runat="server" Text='<%# GetProVarText(Eval("ProVarState")) %>' />
</ItemTemplate>
<EditItemTemplate>
<asp:DropDownList ID="ddlProVarEdit" runat="server"
SelectedValue='<%# Bind("ProVarState") %>'>
<asp:ListItem Text="硬件" Value="HW" />
<asp:ListItem Text="軟件" Value="SW" />
<asp:ListItem Text="網絡" Value="NW" />
<asp:ListItem Text="其他" Value="OT" />
</asp:DropDownList>
</EditItemTemplate>
</asp:TemplateField>
// 後台輔助方法
public string GetProVarText(object value) {
var dict = new Dictionary { {"HW","硬件"},{"SW","軟件"},{"NW","網絡"},{"OT","其他"} };
return dict.TryGetValue(value?.ToString(), out var text) ? text : "未知";
}
編輯模式下 Bind("ProVarState") 自動處理:顯示時讀取值設置 SelectedValue,更新時提取 SelectedValue 寫回數據源,**無需手動編寫 RowDataBound/RowUpdating 代碼**。
ItemTemplate + HiddenField 存儲值 + RowDataBound 設置選中(本文方案)。EditItemTemplate + Bind("FieldName") 雙向綁定,簡潔可靠。RowDataBound 中從緩存/數據庫填充 ddl.Items,再設置選中。ListItem 集合,避免每行重複創建。掌握 RowDataBound 階段控件查找與值綁定模式,配合 Bind 雙向綁定機制,能輕鬆應對 GridView 中複雜下拉框、複選框、日期控件的數據同步需求。