如何避免TextMode为Date的asp:TextBox出现逗号分隔双日期值
ASP.NET 4.5 TextBox(TextMode=Date)回调时Text值重复问题
问题场景
我有一个ASP.Net 4.5 Web应用程序,在Sample.aspx页面中包含一个asp:TextBox控件,代码如下:
<asp:TextBox ID="dteEffective" Width="90" runat="server" TextMode="Date" Font-Names="Arial"></asp:TextBox> <button id="btnSubmit" type="button" clientidmode="Static" runat="server" class="aspBtn" onclick="validateData();" style="width: 100px;">Save</button> <script type="text/javascript"> function validateData() { var strDate = document.getElementById('<%= dteEffective.ClientID %>').value; // 这里能拿到正确值"2023-06-12" callbackValidate_Callback(null, null); // 调用后台的ValidateCallback() } ... </script>
在Sample.aspx.cs的Page_Load中,将控件初始化为当前日期:
protected void Page_Load(object sender, EventArgs e) { if (!Page.IsPostBack) { ... dteEffective.Text = DateTime.Now.ToString("yyyy-MM-dd"); } }
控件正确显示06/13/2023,当修改为06/12/2023并点击Save按钮触发自定义回调ValidateCallback()后,发现dteEffective.Text的值并非预期的"2023-06-12",而是"2023-06-12,2023-06-13"(修改后的日期+逗号+初始日期),导致日期验证出错。回调代码如下:
protected void ValidateCallback(CallbackControl sender, EventArgs e) { string validationType = sender.ArgumentParameter.ToString(); message = null; string strDateEffective = dteEffective.Text; // 这里拿到的是"2023-06-12,2023-06-13" try { Validator validator = new Validator(); DateTime dteEff; DateTime.TryParse(dteEffective.Text, out dteEff); // 验证失败 validator.CheckDateErrors(String.Empty, "Effective Date", dteEffective, DateTime.Now, Validator.DateOptions.Required | Validator.DateOptions.NotBefore1935); validator.ValidateFields(); message = validator.JavascriptErrorString(hdSoftEdits); // hdSoftEdits是错误提示用的隐藏域 } catch (Exception ex) { Common.LogError(ex); message = "ERROR: " + ex.Message; } sender.RenderedOutput = message; }
原因分析
这是ASP.NET 4.5中TextMode="Date"的TextBox控件在自定义回调场景下的状态恢复异常:
- 当控件设置为
TextMode="Date"时,内部会同时维护用户提交的新值和ViewState中存储的初始值 - 自定义回调的状态恢复逻辑未正确处理这两个值的优先级,导致两个值被错误地拼接成逗号分隔的字符串返回给
Text属性 - 标准PostBack流程会正确覆盖旧值,但自定义回调的处理逻辑与标准PostBack不同,触发了这个bug
解决方法
方法1:从回调参数传递客户端的日期值
直接把客户端获取到的正确日期值作为参数传递给回调,绕过服务器端控件的Text属性:
修改前端validateData函数:
function validateData() { var strDate = document.getElementById('<%= dteEffective.ClientID %>').value; callbackValidate_Callback(strDate, null); // 将日期作为参数传入回调 }
后台回调函数中直接使用传递的参数:
protected void ValidateCallback(CallbackControl sender, EventArgs e) { string strDateEffective = sender.ArgumentParameter.ToString(); // 获取客户端传递的正确日期 message = null; try { Validator validator = new Validator(); DateTime dteEff; if(DateTime.TryParse(strDateEffective, out dteEff)) { validator.CheckDateErrors(String.Empty, "Effective Date", strDateEffective, DateTime.Now, Validator.DateOptions.Required | Validator.DateOptions.NotBefore1935); validator.ValidateFields(); message = validator.JavascriptErrorString(hdSoftEdits); } else { message = "ERROR: 无效的生效日期"; } } catch (Exception ex) { Common.LogError(ex); message = "ERROR: " + ex.Message; } sender.RenderedOutput = message; }
方法2:直接从Request.Form中获取最新值
表单提交的最新值会存储在Request.Form中,通过控件的UniqueID可以直接获取正确值,绕过控件的错误状态:
protected void ValidateCallback(CallbackControl sender, EventArgs e) { string strDateEffective = Request.Form[dteEffective.UniqueID]; // 直接从表单取最新值 // 后续验证逻辑使用这个值 // ... 其余代码不变 }
方法3:调整控件初始化方式(可选)
避免在Page_Load中直接赋值Text属性,改用数据绑定的方式,确保ViewState正确维护控件状态:
protected void Page_Load(object sender, EventArgs e) { if (!Page.IsPostBack) { // 改用绑定表达式 dteEffective.DataBind(); } }
同时在前端控件中设置绑定:
<asp:TextBox ID="dteEffective" Width="90" runat="server" TextMode="Date" Font-Names="Arial" Text='<%# DateTime.Now.ToString("yyyy-MM-dd") %>'></asp:TextBox>
这个方法效果不如前两个直接,仅作为备选。
内容的提问来源于stack exchange,提问作者Petronius
相关产品推荐
相关产品推荐

