Repeater生成的ASP.NET DropDownList首次选择不触发OnSelectedIndexChanged
问题原因分析
动态修改控件ID导致回发时控件树不匹配
你在ItemDataBound事件中动态修改了DropDownList的ID并设置ClientIDMode=Static,首次页面渲染后客户端的控件ID是_ddlFieldXXX。但首次回发时,如果Repeater仅在!IsPostBack时绑定数据源,ItemDataBound不会触发,服务器端重建的DropDownList仍使用原始IDddlRepeater,导致服务器无法将回发的表单数据与控件匹配,最终事件不触发、状态丢失。而第二次回发时,若Repeater重新绑定,控件ID被修改为匹配的_ddlFieldXXX,所以功能恢复正常。DataBind顺序错误覆盖SelectedValue
代码中先设置SelectedValue再调用DataBind(),DataBind()会重置控件的选中状态,导致首次绑定的选中值被覆盖,这也会影响ViewState的正确存储。
解决方案
方案1:移除动态修改ID的逻辑,保留原始控件ID
不需要修改DropDownList的ID,通过自定义属性区分不同下拉框,这是最优方案:
- 修改
ItemDataBound事件代码:
protected void rptTemplateFields_OnItemDataBound(object sender, RepeaterItemEventArgs e) { if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem) { dynamic field = e.Item.DataItem; BugFieldName fieldName = field?.FieldName; string fieldContent = field?.FieldContent; var allowedValues = GenerateAllowedValues(fieldName); if (!fieldName.IsNullOrUnsetValue() && !allowedValues.IsNullOrEmpty()) { var ddl = e.Item.FindControl("ddlRepeater") as DropDownList; // 添加自定义属性存储fieldName,替代动态修改ID ddl.Attributes.Add("data-fieldname", fieldName.ToString()); // 移除ClientIDMode=Static,保持默认规则避免控件树不匹配 // 调整顺序:先绑定数据源,再设置选中值 ddl.DataSource = allowedValues; ddl.DataBind(); // 确保空选项存在(因AppendDataBoundItems=true,原空选项会保留,可根据需求调整) if (!ddl.Items.Contains(new ListItem("", ""))) { ddl.Items.Insert(0, new ListItem("", "")); } // 设置选中值 if (allowedValues.Contains(fieldContent)) { ddl.SelectedValue = fieldContent; } ddl.Visible = true; } } }
- 修改
SelectedIndexChanged事件,通过自定义属性获取标识:
protected void ddlRepeater_SelectedIndexChanged(object sender, EventArgs e) { var ddlRepeater = sender as DropDownList; string fieldName = ddlRepeater.Attributes["data-fieldname"]; var state = (string)ViewState[fieldName]; if (state != ddlRepeater.SelectedValue) { ViewState[fieldName] = ddlRepeater.SelectedValue; } }
方案2:确保Repeater在每次回发时都重新绑定(不推荐)
如果必须保留动态ID,需要确保Repeater在**每次页面加载(包括回发)**时都重新绑定数据源,让ItemDataBound触发以同步控件ID:
在Page_Load事件中添加:
protected void Page_Load(object sender, EventArgs e) { // 不要加!IsPostBack判断,确保每次回发都绑定Repeater rptTemplateFields.DataSource = rptrDataSource; rptTemplateFields.DataBind(); }
同时必须调整DataBind顺序(先绑定再设置SelectedValue),但此方法会增加服务器负载,仅作为备选方案。
额外注意事项
- 确保Repeater和DropDownList的
ViewState处于启用状态(默认启用,无需额外设置)。 - 若不需要保留初始空选项,可移除
AppendDataBoundItems=true,避免重复添加空项。
内容的提问来源于stack exchange,提问作者zkatancik
相关产品推荐
相关产品推荐

