ASP.NET GridView动态行TextBox字符计数状态持久化问题求助
问题描述
已实现ASP.NET GridView动态添加行功能,同时通过jQuery完成TextBox的字符计数功能,运行正常。但存在问题:通过服务端代码添加新行时,原有行的字符计数状态会被重置(例如第一行剩余字符数应为0,添加新行后变回10)。原本计划通过Ajax结合Session存储计数状态,但方案繁琐,寻求更优实现方式,既要正确显示字符计数,又能在添加新行时持久化计数状态。
现有实现代码
C# 代码
private void SetInitialRow() { DataTable dt = new DataTable(); DataRow dr = null; dt.Columns.Add(new DataColumn("RowNumber", typeof(string))); dt.Columns.Add(new DataColumn("Column1", typeof(string))); dt.Columns.Add(new DataColumn("Column2", typeof(string))); dt.Columns.Add(new DataColumn("Column3", typeof(string))); dr = dt.NewRow(); dr["RowNumber"] = 1; dr["Column1"] = string.Empty; dr["Column2"] = string.Empty; dr["Column3"] = string.Empty; dt.Rows.Add(dr); //Store the DataTable in ViewState ViewState["CurrentTable"] = dt; Gridview1.DataSource = dt; Gridview1.DataBind(); } private void AddNewRowToGrid() { int rowIndex = 0; if (ViewState["CurrentTable"] != null) { DataTable dtCurrentTable = (DataTable)ViewState["CurrentTable"]; DataRow drCurrentRow = null; if (dtCurrentTable.Rows.Count > 0) { for (int i = 1; i <= dtCurrentTable.Rows.Count; i++) { //extract the TextBox values TextBox box1 = (TextBox)Gridview1.Rows[rowIndex].Cells[1].FindControl("TextBox1"); TextBox box2 = (TextBox)Gridview1.Rows[rowIndex].Cells[2].FindControl("TextBox2"); TextBox box3 = (TextBox)Gridview1.Rows[rowIndex].Cells[3].FindControl("TextBox3"); drCurrentRow = dtCurrentTable.NewRow(); drCurrentRow["RowNumber"] = i + 1; dtCurrentTable.Rows[i - 1]["Column1"] = box1.Text; dtCurrentTable.Rows[i - 1]["Column2"] = box2.Text; dtCurrentTable.Rows[i - 1]["Column3"] = box3.Text; rowIndex++; } dtCurrentTable.Rows.Add(drCurrentRow); ViewState["CurrentTable"] = dtCurrentTable; Gridview1.DataSource = dtCurrentTable; Gridview1.DataBind(); } } else { Response.Write("ViewState is null"); } //Set Previous Data on Postbacks SetPreviousData(); } private void SetPreviousData() { int rowIndex = 0; if (ViewState["CurrentTable"] != null) { DataTable dt = (DataTable)ViewState["CurrentTable"]; if (dt.Rows.Count > 0) { for (int i = 0; i < dt.Rows.Count; i++) { TextBox box1 = (TextBox)Gridview1.Rows[rowIndex].Cells[1].FindControl("TextBox1"); TextBox box2 = (TextBox)Gridview1.Rows[rowIndex].Cells[2].FindControl("TextBox2"); TextBox box3 = (TextBox)Gridview1.Rows[rowIndex].Cells[3].FindControl("TextBox3"); if (Session["val"] != null) { List<string> aLst = (List<string>)Session["val"]; foreach (var item in aLst) { Label lbl1 = (Label)Gridview1.Rows[rowIndex].Cells[3].FindControl("lblCount"); lbl1.Text = (10 - item.Length + " characters remain").ToString(); } } box1.Text = dt.Rows[i]["Column1"].ToString(); box2.Text = dt.Rows[i]["Column2"].ToString(); box3.Text = dt.Rows[i]["Column3"].ToString(); rowIndex++; } } } } protected void Page_Load(object sender, EventArgs e) { if (!Page.IsPostBack) { SetInitialRow(); } } protected void ButtonAdd_Click(object sender, EventArgs e) { AddNewRowToGrid(); }
ASP.NET 代码
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script> <script type="text/javascript"> $(document).ready(function () { $("table[id*=Gridview1] input[id*=TextBox1]").keyup(function () { var length = parseInt($(this).attr("maxlength")); $(this).next(".count").html(length - $(this).val().length + " characters remain"); var val = $("table[id*=Gridview1] input[id*=TextBox1]").val(); debugger; $.ajax({ type: "POST", url: "/Default16.aspx/GetListofString", data: JSON.stringify({ name: val }), contentType: "application/json; charset=utf-8", dataType: "json", success: function (values) { $.each(values, function (i, value) { //alert(value); $(this).next(".count").html(length - value.length + " characters remain"); }); } }); }) }) </script> <div> <asp:gridview ID="Gridview1" runat="server" ShowFooter="true" AutoGenerateColumns="false"> <Columns> <asp:BoundField DataField="RowNumber" HeaderText="Row Number" /> <asp:TemplateField HeaderText="Header 1"> <ItemTemplate> <asp:TextBox ID="TextBox1" runat="server" MaxLength="10"></asp:TextBox> <%--<span class="font-sm countDefenceCaseName">10 characters remain</span>--%> <asp:Label ID="lblCount" runat="server" CssClass="font-sm count" Text="10 characters remain"></asp:Label> </ItemTemplate> </asp:TemplateField> <asp:TemplateField HeaderText="Header 2"> <ItemTemplate> <asp:TextBox ID="TextBox2" runat="server"></asp:TextBox> </ItemTemplate> </asp:TemplateField> <asp:TemplateField HeaderText="Header 3"> <ItemTemplate> <asp:TextBox ID="TextBox3" runat="server"></asp:TextBox> </ItemTemplate> <FooterStyle HorizontalAlign="Right" /> <FooterTemplate> <asp:Button ID="ButtonAdd" runat="server" Text="Add New Row" onclick="ButtonAdd_Click" /> </FooterTemplate> </asp:TemplateField> </Columns> </asp:gridview> </div>
原计划的繁琐方案
[System.Web.Services.WebMethod(EnableSession = true)] public static List<string> GetListofString(string name) { List<string> aLst; if (HttpContext.Current.Session["val"] == null) { aLst = new List<string>(); aLst.Add(name); } else { aLst = (List<string>)HttpContext.Current.Session["val"]; aLst.Add(name); } return aLst; }
更优解决方案
有两种简单可行的方案,无需Session或复杂Ajax:
方案一:服务端绑定直接计算剩余字符数
修改SetPreviousData方法,去掉Session相关逻辑,直接根据TextBox的文本长度计算剩余字符数,同时修正Label的查找位置(原代码错误地在Cells[3]查找,实际Label和TextBox在同一Cells[1]):
private void SetPreviousData() { int rowIndex = 0; if (ViewState["CurrentTable"] != null) { DataTable dt = (DataTable)ViewState["CurrentTable"]; if (dt.Rows.Count > 0) { for (int i = 0; i < dt.Rows.Count; i++) { TextBox box1 = (TextBox)Gridview1.Rows[rowIndex].Cells[1].FindControl("TextBox1"); TextBox box2 = (TextBox)Gridview1.Rows[rowIndex].Cells[2].FindControl("TextBox2"); TextBox box3 = (TextBox)Gridview1.Rows[rowIndex].Cells[3].FindControl("TextBox3"); // 计算并更新剩余字符数 Label lblCount = (Label)Gridview1.Rows[rowIndex].Cells[1].FindControl("lblCount"); int maxLength = box1.MaxLength; int remaining = maxLength - box1.Text.Length; lblCount.Text = $"{remaining} characters remain"; box1.Text = dt.Rows[i]["Column1"].ToString(); box2.Text = dt.Rows[i]["Column2"].ToString(); box3.Text = dt.Rows[i]["Column3"].ToString(); rowIndex++; } } } }
方案二:客户端页面加载后统一更新计数
利用ASP.NET的页面生命周期,在每次页面加载(包括PostBack后)重新计算所有TextBox的剩余字符数,无需服务端额外处理:
修改前端脚本,添加统一更新函数,并处理PostBack后的事件:
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script> <script type="text/javascript"> // 统一更新所有TextBox的字符计数 function updateCharCounts() { $("table[id*=Gridview1] input[id*=TextBox1]").each(function() { var maxLength = parseInt($(this).attr("maxlength")); var remaining = maxLength - $(this).val().length; $(this).next(".count").html(remaining + " characters remain"); }); } $(document).ready(function () { // 初始加载时更新 updateCharCounts(); // 键盘输入时更新当前行 $("table[id*=Gridview1] input[id*=TextBox1]").keyup(function () { var maxLength = parseInt($(this).attr("maxlength")); var remaining = maxLength - $(this).val().length; $(this).next(".count").html(remaining + " characters remain"); }); }); // 处理PostBack(添加新行)后的更新 Sys.WebForms.PageRequestManager.getInstance().add_endRequest(function() { updateCharCounts(); }); </script>
同时可以删除原代码中Session相关的逻辑和不必要的Ajax调用,简化实现。
内容的提问来源于stack exchange,提问作者user8512043
相关产品推荐
相关产品推荐

