为什么asp:UpdatePanel中后台修改的asp:TextBox值不生效?
解决方案
你要实现的功能完全可行,问题出在UpdatePanel的更新时机和回发时控件赋值的逻辑错误,具体修复方案如下:
核心问题原因
- 你当前用Timer触发两次回发的逻辑存在缺陷:第一次点击GridView行触发的回发中,你给TextBox、Label赋值,但这次回发不会触发UpdatePanel重绘,回发结束后服务端页面对象销毁,你赋的新值不会被保留到下次回发。第二次Timer触发的回发中,你仅调用了UpdatePanel的Update()方法,没有重新给控件赋值,控件值是从ViewState恢复的旧值,所以出现更新不一致的问题。
- 代码存在ID不匹配问题:前端UpdatePanel的ID是
UpdatePanel1,但后台Tick事件中调用的是upnlContacts.Update(),ID不一致也会导致UpdatePanel无法正常刷新。
修复方案
方案1 快速修复现有逻辑
- 先同步UpdatePanel的ID,要么把前端ID改为
upnlContacts,要么把后台的upnlContacts.Update()改为UpdatePanel1.Update()。 - 将加载联系人数据的逻辑移到Timer的Tick事件中,用ViewState持久化选中的联系人ID,修改后代码如下:
// 用ViewState存储选中的联系人ID,跨回发持久化 private int SelectedPersonID { get { return ViewState["SelectedPersonID"] == null ? 0 : (int)ViewState["SelectedPersonID"]; } set { ViewState["SelectedPersonID"] = value; } } private void LoadSelectedContact(int personID) { DataTable dt = GetProfileContacts(personID, true); if (dt.Rows.Count > 0) { DataRow row = dt.Rows[0]; lblContactAccountID.Text = row["PersonID"].ToString(); txtContactFirstName.Text = row["FirstName"].ToString(); // 其余字段赋值 } } protected void gvContacts_RowSelected(object sender, GridViewCommandEventArgs e) { if (e.CommandName == "Selected") { GridViewRow row = (GridViewRow)((Control)e.CommandSource).NamingContainer; // 用DataKeys读取PersonID,比读单元格文本更可靠 int personID = Int32.Parse(gvContacts.DataKeys[row.RowIndex]["PersonID"].ToString()); SelectedPersonID = personID; ContactsTimer.Enabled = true; } } protected void ContactsTimer_Tick(object sender, EventArgs e) { ContactsTimer.Enabled = false; if(SelectedPersonID > 0) { LoadSelectedContact(SelectedPersonID); } UpdatePanel1.Update(); }
方案2 更优雅的实现(推荐,完全移除Timer)
Timer触发更新的方式冗余且有延迟,直接将GridView的RowCommand事件设为UpdatePanel的异步触发器即可,不需要额外Timer控件:
前端修改
- 移除Timer控件
- 修改UpdatePanel的触发器配置:
<asp:UpdatePanel ID="UpdatePanel1" runat="server" UpdateMode="Conditional" > <ContentTemplate> <asp:Label ID="lblContactAccountID" runat="server"/> <asp:TextBox ID="txtContactFirstName" runat="server"/> </ContentTemplate> <Triggers> <asp:AsyncPostBackTrigger ControlID="gvContacts" EventName="RowCommand" /> </Triggers> </asp:UpdatePanel>
后台修改
- 移除所有Timer相关代码,直接在RowCommand事件中赋值后触发UpdatePanel更新:
protected void gvContacts_RowSelected(object sender, GridViewCommandEventArgs e) { if (e.CommandName == "Selected") { GridViewRow row = (GridViewRow)((Control)e.CommandSource).NamingContainer; int personID = Int32.Parse(gvContacts.DataKeys[row.RowIndex]["PersonID"].ToString()); LoadSelectedContact(personID); UpdatePanel1.Update(); } } private void LoadSelectedContact(int personID) { DataTable dt = GetProfileContacts(personID, true); if (dt.Rows.Count > 0) { DataRow row = dt.Rows[0]; lblContactAccountID.Text = row["PersonID"].ToString(); txtContactFirstName.Text = row["FirstName"].ToString(); // 其余字段赋值 } }
额外注意
确保Page_Load中的初始绑定逻辑加了!IsPostBack判断,避免回发时覆盖控件的新值:
protected void Page_Load(object sender, EventArgs e) { if(!IsPostBack) { // 初始绑定GridView、加载默认联系人的逻辑写在这里 } }
内容的提问来源于stack exchange,提问作者JonV
相关产品推荐
相关产品推荐

