GridView内嵌DropDownList回发后首次选值丢失问题求助
看起来你遇到的问题是GridView编辑行里的DropDownList第一次选值后,回发就变回初始状态,第二次才正常保留。这其实是ASP.NET WebForms里很常见的视图状态与事件生命周期冲突问题,我来帮你拆解解决:
问题根源
每次DropDownList触发AutoPostBack回发时,你的GridView2_ddl(也就是RowDataBound事件)会重新执行。之前的代码里,你每次都会重新绑定DropDownList数据,还强制把SelectedValue设为数据源的原始ID——但回发时GridView并没有重新绑定数据源,e.Row.DataItem实际上是null,这就导致你要么设置了错误值,要么直接覆盖了用户刚选的结果。第一次回发被重置,第二次因为编辑状态持续且没有再强制覆盖,才看起来正常。
解决方案
我们需要修改代码,区分「首次进入编辑模式」和「回发后的编辑状态」,确保回发时保留用户选择的值:
1. 补充GridView的正确绑定逻辑
你原来的Page_Load里只绑定了空DataTable,这肯定不对,先补充一个绑定GridView数据源的方法:
private void BindGridView2() { string constr = ConfigurationManager.ConnectionStrings["DBConnectionString"].ConnectionString; using (SqlConnection con = new SqlConnection(constr)) { // 替换成你实际获取GridView数据的SQL语句 using (SqlCommand cmd = new SqlCommand("SELECT ID, MonitorDetailsID FROM YourActualTableName")) { using (SqlDataAdapter sda = new SqlDataAdapter(cmd)) { DataTable dt = new DataTable(); sda.Fill(dt); GridView2.DataSource = dt; GridView2.DataBind(); } } } }
然后修改Page_Load,调用这个方法加载数据:
protected void Page_Load(object sender, EventArgs e) { IntranetCore masterpage = (IntranetCore)(Page.Master); masterpage.PageTitle = "Maintain Database Tables"; masterpage.ShowPageLastUpdated = false; Master.Page.Title = "test"; this.Title = "Maintain Database Tables"; if (!IsPostBack) { BindGridView2(); // 首次加载时绑定实际数据源 } }
2. 处理RowEditing事件,保存原始ID
当用户进入编辑模式时,把当前行的原始MonitorDetailsID保存到ViewState,方便后续判断:
protected void GridView2_RowEditing(object sender, GridViewEditEventArgs e) { GridView2.EditIndex = e.NewEditIndex; // 获取当前行的原始MonitorDetailsID并保存到ViewState int originalID = Convert.ToInt32(GridView2.DataKeys[e.NewEditIndex].Values["MonitorDetailsID"]); ViewState["OriginalMonitorDetailsID"] = originalID; // 重新绑定GridView,确保编辑状态正确显示 BindGridView2(); }
3. 修改RowDataBound事件,正确设置选中值
修改你的GridView2_ddl方法,回发时优先使用用户选择的值,而不是强制设置原始值:
protected void GridView2_ddl(object sender, GridViewRowEventArgs e) { if ((e.Row.RowState & DataControlRowState.Edit) > 0) { string constr = ConfigurationManager.ConnectionStrings["DBConnectionString"].ConnectionString; using (SqlConnection con = new SqlConnection(constr)) { using (SqlCommand cmd = new SqlCommand(@"select top 100 ID, name from db_monitordetails;")) { using (SqlDataAdapter sda = new SqlDataAdapter()) { cmd.Connection = con; sda.SelectCommand = cmd; using (DataTable dt = new DataTable()) { sda.Fill(dt); DropDownList ddl = (DropDownList)e.Row.FindControl("txtMonitorDetailsID1"); ddl.DataSource = dt; ddl.DataValueField = "ID"; ddl.DataTextField = "name"; ddl.AppendDataBoundItems = true; ddl.Items.Clear(); // 先清空,避免重复添加默认项 ddl.Items.Insert(0, new ListItem("--Select Monitor details--", "0")); ddl.DataBind(); string selectedValue = null; // 回发时,从Request中获取用户实际选择的值 if (IsPostBack) { string ddlClientID = ddl.ClientID; selectedValue = Request.Form[ddlClientID]; } // 如果没有回发值,用原始的ID if (string.IsNullOrEmpty(selectedValue)) { selectedValue = ViewState["OriginalMonitorDetailsID"]?.ToString(); } // 确保选中值存在,再设置 if (!string.IsNullOrEmpty(selectedValue) && ddl.Items.FindByValue(selectedValue) != null) { ddl.SelectedValue = selectedValue; } } } } } } }
4. 修正GridView的DataKeyNames
你原来的GridView只把ID设为DataKeyNames,需要加上MonitorDetailsID,这样才能在RowEditing里获取到原始值:
<asp:GridView runat="server" ID="GridView2" Width="100%" AutoGenerateColumns="False" ShowFooter="True" DataKeyNames="ID,MonitorDetailsID" OnPageIndexChanging="GridView2_PageIndexChanging" OnRowDeleting="GridView2_RowDeleting" OnRowEditing="GridView2_RowEditing" OnRowUpdating="GridView2_RowUpdating" OnRowCancelingEdit="GridView2_RowCancelingEdit" OnRowCommand="GridView2_RowCommand" HeaderStyle-CssClass="GVFixedHeader" FooterStyle-CssClass="GVFixedFooter" OnRowDataBound="GridView2_ddl" EnableViewState="true" > <!-- 其他列代码不变 --> </asp:GridView>
这样修改后,第一次选择DropDownList的值回发时,就能正确保留用户选择的结果了。
内容的提问来源于stack exchange,提问作者Aarthi Muthusami

