You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 00:35:19