【问题标题】:Stop Textbox in GridView Losing Data on Postback停止 GridView 中的文本框在回发时丢失数据
【发布时间】:2025-12-25 21:05:16
【问题描述】:

我有一个 GridView,我通过 button_OnClick 事件动态添加行,这会从 DropDownList 添加一个带有产品名称和产品 ID 的新行,并且还包含一个带有空文本框的列供用户输入。

我的问题是,当我测试它并在文本框中输入数据,然后添加另一个产品时,回发导致我的数据丢失(正确的行数仍然存在产品名称/ID)。

                            <asp:GridView runat="server" ID="grdSelectedProducts" BorderWidth="1px" CellPadding="3" CellSpacing="2" AutoGenerateColumns="False" OnRowDataBound="grdSelectedProducts_OnRowDataBound" ShowHeaderWhenEmpty="True" DataKeyNames="ProductId"
                                OnRowCommand="grdSelectedProducts_RowCommand" OnRowDeleted="grdSelectedProducts_RowDeleted" OnRowDeleting="grdSelectedProducts_RowDeleting" EmptyDataText="Please select a Product and click 'Add'" EnableViewState="True">
                                <Columns>
                                    <asp:BoundField DataField="Product" HeaderText="Product" ReadOnly="False"/>
                                    <asp:TemplateField HeaderText="Description">
                                        <ItemTemplate>
                                                 <asp:TextBox runat="server" ID="txtDescriptionEntry" Text="" style="width:98% !important" EnableViewState="True"></asp:TextBox>
                                        </ItemTemplate>
                                    </asp:TemplateField>
                                    <asp:TemplateField>
                                        <ItemTemplate>
                                            <asp:LinkButton runat="server" ID="linkDelete" runat="server" CommandName="Delete" CommandArgument="<%# Container.DataItemIndex %>">Remove</asp:LinkButton>
                                        </ItemTemplate>
                                    </asp:TemplateField>
                                    <asp:BoundField DataField="ProductId" HeaderText="ProductId" ReadOnly="False" Visible="False" />
                                </Columns>
                            </asp:GridView>

如何避免回发废弃所创建的每个 txtDescriptionEntry 上的数据?这些文本框的数量可能在 0 到无限个之间,因此我在任何时候都不会有确切的名称。

编辑,根据下面的评论,我将包含有关如何将行添加到网格的代码: 私有数据表 ProductDataTable { 获取 {return ViewState["ProductDataTable"] 作为 DataTable ??新数据表(); } 设置 { ViewState["ProductDataTable"] = value; } }

    private DataTable CreateDataTable(bool isAddingValue, string selectedProduct, string selectedId)
    {
        // if isAddingValue is FALSE then it isn't from a button click to add a Product, it is just
        // a call to create the datatable

        DataTable dataTable = ProductDataTable;
        if (!dataTable.Columns.Contains("Product"))
        {
            dataTable.Columns.Add("Product");
            dataTable.Columns.Add("Description"); // This column is free format text that the user enters.
            dataTable.Columns.Add("ProductId");
        }

        if (isAddingValue)
        {
            // Get the data from ViewState
            //dataTable = ProductDataTable;
            DataRow dataRow;
            dataRow = dataTable.NewRow();
            dataRow["Product"] = selectedProduct;
            dataRow["ProductId"] = selectedId;
            dataTable.Rows.Add(dataRow);
        }
        else
        {
            grdSelectedProducts.DataSource = null;
            grdSelectedProducts.DataSource = ProductDataTable;
            grdSelectedProducts.DataBind();

        }
        // Save the data back to ViewState
        ProductDataTable = dataTable;

        return dataTable;
    }

    protected void btnAddProduct_OnClick(object sender, EventArgs e)
    {
        string selectedProduct = ddlProduct.SelectedItem.Text;
        string selectedId = ddlProduct.SelectedValue;

        DataTable dataTable = CreateDataTable(true, selectedProduct, selectedId);

        grdSelectedProducts.DataSource = dataTable;
        grdSelectedProducts.DataBind();

    }

    protected void grdSelectedProducts_RowCommand(object sender, GridViewCommandEventArgs e)
    {
        if (e.CommandName == "Delete")
        {
            if (!string.IsNullOrEmpty(e.CommandArgument.ToString()))
            {
                int rowIndex = Convert.ToInt32(e.CommandArgument);
                DataTable table = CreateDataTable(false, string.Empty, string.Empty);
                table.Rows.RemoveAt(rowIndex);
                grdSelectedProducts.DataSource = table;
                grdSelectedProducts.DataBind();
            }
        }
    }

并且在 Page_Load 事件中,如果它不是 PostBack 也有一个空列表的绑定

        grdSelectedProducts.DataSource = new List<Products>();
        grdSelectedProducts.DataBind();

【问题讨论】:

  • 如何在 GridView 中添加数据
  • @Adil 我已经更新了帖子。
  • 当 btnAddProduct 回发时,您在 GridView 中没有得到记录吗?您是否也将 GridView 绑定到其他任何地方?
  • Page_load 事件中有一个绑定,它将一个空列表绑定到网格,并且在删除一行时有绑定,但除此之外别无他法。我再次更新了正文。
  • 能否请您将 page_load 也添加到代码中。以及您如何存储文本数据。你把它推到数据库然后拉回来吗?

标签: asp.net gridview postback


【解决方案1】:

我想出了这个,不是最好的解决方案(所以我可能不会推荐它),但它让我摆脱了困境。

我使用了OnRowDataBound 事件,因此对于绑定到表的每一行,我将使用RowIndexDataTable 中获取适当的行,然后分配文本框(也通过索引)来自 DT 的值。下面的例子。

    protected void grdSelectedproducts_OnRowDataBound(object sender, GridViewRowEventArgs e)
    {
        if (e.Row.RowIndex > -1)
        {
            TextBox txtDescription = e.Row.FindControl("txtDescriptionEntry") as TextBox;

            if (txtDescription != null)
            {
                DataTable dt = ProductDataTable;
                DataRow row = dt.Rows[e.Row.RowIndex] as DataRow;
                txtDescription.Text = row[1].ToString();
            }
        }
    }

【讨论】: