65.9K
CodeProject 正在变化。 阅读更多。
Home

在GridView 中动态添加和删除行,并一次性保存所有行

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.43/5 (4投票s)

2016 年 6 月 30 日

CPOL

6分钟阅读

viewsIcon

40523

downloadIcon

845

一个简单的演示,展示如何使用TextBox和DropDownList在GridView中动态添加行,在回发时保留值,并使用SQLBulkCopy一次性保存所有行值。

引言

多年前,我写了一系列文章,介绍了如何在GridView控件中添加动态文本框、动态下拉列表以及两者的组合。我还发布了几篇关于如何删除动态创建的行以及如何一次性保存它们。您可以在这里找到这些文章系列:ASP.NET and Dynamic Controls

直到现在,仍然经常有人问“如何在点击按钮时在GridView中生成动态控件”。所以在这篇文章中,我将把所有内容汇总到一处,方便参考。以下是您将看到的主要功能:

  • 添加包含TextBox和DropDownList的行
  • 在回发时保留TextBox值和DropDownList选中的值
  • 能够删除行
  • 一次性保存所有值
     

使用代码

要开始,请启动Visual Studio,然后添加一个新的WebForm页面。向页面添加一个GridView控件。这是GridView的HTML标记:

ASPX

<asp:Label ID="lblMessage" runat="server" ForeColor="Green" />
        <asp:gridview ID="Gridview1"  runat="server"  ShowFooter="true"
                             AutoGenerateColumns="false"
                             OnRowCreated="Gridview1_RowCreated">
            <Columns>
                <asp:BoundField DataField="RowNumber" HeaderText="Row Number" />
                <asp:TemplateField HeaderText="Header 1">
                    <ItemTemplate>
                        <asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
                    </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:DropDownList ID="DropDownList1" runat="server"
                                          AppendDataBoundItems="true">
                             <asp:ListItem Value="-1">Select</asp:ListItem>
                        </asp:DropDownList>
                    </ItemTemplate>
                </asp:TemplateField>
                <asp:TemplateField HeaderText="Header 4">
                    <ItemTemplate>
                        <asp:DropDownList ID="DropDownList2" runat="server"
                                          AppendDataBoundItems="true">
                             <asp:ListItem Value="-1">Select</asp:ListItem>
                        </asp:DropDownList>
                    </ItemTemplate>
                    <FooterStyle HorizontalAlign="Right" />
                    <FooterTemplate>
                         <asp:Button ID="ButtonAdd" runat="server" 
                                     Text="Add New Row" 
                                     onclick="ButtonAdd_Click"
                                    OnClientClick="return ValidateEmptyValue();" />
                    </FooterTemplate>
                </asp:TemplateField>
                <asp:TemplateField>
                    <ItemTemplate>
                        <asp:LinkButton ID="LinkDelete" runat="server" 
                                        onclick="LinkDelete_Click">Remove</asp:LinkButton>
                    </ItemTemplate>
                </asp:TemplateField>
            </Columns>
        </asp:gridview> 

从上面的标记可以看出,我设置了一个BoundField来显示行号,以及一些TemplateField列,以便在添加新行时GridView会自动生成一行TextBoxesDropDownLists。您还会看到我在最后一个DropDownLists列的FooterTemplate下添加了一个Button控件,并在GridView的最后一列添加了一个LinkButton用于删除行。

注意:由于我们在GridView的页脚添加了一个控件,因此请确保在GridView中将ShowFooter设置为TRUE。

后台代码

为了演示的简单性,我使用ArrayList作为DropDownLists的数据源创建了一个模拟数据。在实际场景中,您可能会查询数据库并将其绑定到您的DropDownList。这是完整的代码:

using System;
using System.Collections;
using System.Data;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Collections.Specialized;
using System.Text;
using System.Data.SqlClient;

namespace WebFormsDemo
{
    public partial class DynamicGrid : System.Web.UI.Page
    {
        private ArrayList GetDummyData() {

            ArrayList arr = new ArrayList();

            arr.Add(new ListItem("Item1", "1"));
            arr.Add(new ListItem("Item2", "2"));
            arr.Add(new ListItem("Item3", "3"));
            arr.Add(new ListItem("Item4", "4"));
            arr.Add(new ListItem("Item5", "5"));

            return arr;
        }

        private void FillDropDownList(DropDownList ddl) {
            ArrayList arr = GetDummyData();

            foreach (ListItem item in arr) {
                ddl.Items.Add(item);
            }
        }

        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)));//for TextBox value 
            dt.Columns.Add(new DataColumn("Column2", typeof(string)));//for TextBox value 
            dt.Columns.Add(new DataColumn("Column3", typeof(string)));//for DropDownList selected item 
            dt.Columns.Add(new DataColumn("Column4", typeof(string)));//for DropDownList selected item 

            dr = dt.NewRow();
            dr["RowNumber"] = 1;
            dr["Column1"] = string.Empty;
            dr["Column2"] = string.Empty;
            dt.Rows.Add(dr);

            //Store the DataTable in ViewState for future reference 
            ViewState["CurrentTable"] = dt;

            //Bind the Gridview 
            Gridview1.DataSource = dt;
            Gridview1.DataBind();

            //After binding the gridview, we can then extract and fill the DropDownList with Data 
            DropDownList ddl1 = (DropDownList)Gridview1.Rows[0].Cells[3].FindControl("DropDownList1");
            DropDownList ddl2 = (DropDownList)Gridview1.Rows[0].Cells[4].FindControl("DropDownList2");
            FillDropDownList(ddl1);
            FillDropDownList(ddl2);
        }

        private void AddNewRowToGrid() {

            if (ViewState["CurrentTable"] != null) {

                DataTable dtCurrentTable = (DataTable)ViewState["CurrentTable"];
                DataRow drCurrentRow = null;

                if (dtCurrentTable.Rows.Count > 0) {
                    drCurrentRow = dtCurrentTable.NewRow();
                    drCurrentRow["RowNumber"] = dtCurrentTable.Rows.Count + 1;

                    //add new row to DataTable 
                    dtCurrentTable.Rows.Add(drCurrentRow);
                   

                    for (int i = 0; i < dtCurrentTable.Rows.Count - 1; i++) {

                        //extract the TextBox values 

                        TextBox box1 = (TextBox)Gridview1.Rows[i].Cells[1].FindControl("TextBox1");
                        TextBox box2 = (TextBox)Gridview1.Rows[i].Cells[2].FindControl("TextBox2");

                        dtCurrentTable.Rows[i]["Column1"] = box1.Text;
                        dtCurrentTable.Rows[i]["Column2"] = box2.Text;

                        //extract the DropDownList Selected Items 

                        DropDownList ddl1 = (DropDownList)Gridview1.Rows[i].Cells[3].FindControl("DropDownList1");
                        DropDownList ddl2 = (DropDownList)Gridview1.Rows[i].Cells[4].FindControl("DropDownList2");

                        // Update the DataRow with the DDL Selected Items 

                        dtCurrentTable.Rows[i]["Column3"] = ddl1.SelectedItem.Text;
                        dtCurrentTable.Rows[i]["Column4"] = ddl2.SelectedItem.Text;

                    }

                    //Store the current data to ViewState for future reference 
                    ViewState["CurrentTable"] = dtCurrentTable;


                    //Rebind the Grid with the current data to reflect changes 
                    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[i].Cells[1].FindControl("TextBox1");
                        TextBox box2 = (TextBox)Gridview1.Rows[i].Cells[2].FindControl("TextBox2");

                        DropDownList ddl1 = (DropDownList)Gridview1.Rows[rowIndex].Cells[3].FindControl("DropDownList1");
                        DropDownList ddl2 = (DropDownList)Gridview1.Rows[rowIndex].Cells[4].FindControl("DropDownList2");

                        //Fill the DropDownList with Data 
                        FillDropDownList(ddl1);
                        FillDropDownList(ddl2);

                        if (i < dt.Rows.Count - 1) {

                            //Assign the value from DataTable to the TextBox 
                            box1.Text = dt.Rows[i]["Column1"].ToString();
                            box2.Text = dt.Rows[i]["Column2"].ToString();

                            //Set the Previous Selected Items on Each DropDownList  on Postbacks 
                            ddl1.ClearSelection();
                            ddl1.Items.FindByText(dt.Rows[i]["Column3"].ToString()).Selected = true;

                            ddl2.ClearSelection();
                            ddl2.Items.FindByText(dt.Rows[i]["Column4"].ToString()).Selected = true;

                        }

                        rowIndex++;
                    }
                }
            }
        }

        protected void Page_Load(object sender, EventArgs e) {
            if (!Page.IsPostBack) {
                SetInitialRow();
            }
        }

        protected void ButtonAdd_Click(object sender, EventArgs e) {
            AddNewRowToGrid();
        }

        protected void Gridview1_RowCreated(object sender, GridViewRowEventArgs e) {
            if (e.Row.RowType == DataControlRowType.DataRow) {
                DataTable dt = (DataTable)ViewState["CurrentTable"];
                LinkButton lb = (LinkButton)e.Row.FindControl("LinkButton1");
                if (lb != null) {
                    if (dt.Rows.Count > 1) {
                        if (e.Row.RowIndex == dt.Rows.Count - 1) {
                            lb.Visible = false;
                        }
                    }
                    else {
                        lb.Visible = false;
                    }
                }
            }
        }

        protected void LinkDelete_Click(object sender, EventArgs e) {
            LinkButton lb = (LinkButton)sender;
            GridViewRow gvRow = (GridViewRow)lb.NamingContainer;
            int rowID = gvRow.RowIndex;
            if (ViewState["CurrentTable"] != null) {

                DataTable dt = (DataTable)ViewState["CurrentTable"];
                if (dt.Rows.Count > 1) {
                    if (gvRow.RowIndex < dt.Rows.Count - 1) {
                        //Remove the Selected Row data and reset row number
                        dt.Rows.Remove(dt.Rows[rowID]);
                        ResetRowID(dt);
                    }
                }

                //Store the current data in ViewState for future reference
                ViewState["CurrentTable"] = dt;

                //Re bind the GridView for the updated data
                Gridview1.DataSource = dt;
                Gridview1.DataBind();
            }

            //Set Previous Data on Postbacks
            SetPreviousData();
        }

        private void ResetRowID(DataTable dt) {
            int rowNumber = 1;
            if (dt.Rows.Count > 0) {
                foreach (DataRow row in dt.Rows) {
                    row[0] = rowNumber;
                    rowNumber++;
                }
            }
        }
    }
}

方法定义

  • GetDummyData():一个返回ArrayList的方法。基本上,此方法包含用于填充DropDownList的静态模拟数据。在处理真实世界场景时,您可能需要使用数据库。
  • FillDropDownList(DropDownList ddl):一个用模拟数据填充DropDownList的方法。
  • SetInitialRow():一个在初始加载时将单行数据绑定到GridView的方法。此方法中定义的DataTable存储在ViewState中,以便在代码中的任何位置都可以跨回发进行引用。基本上,此表将作为GridView的原始DataSource。请记住,这只是为了演示,因此在使用ViewState时要小心,以避免页面性能问题。此外,ViewState的大小有限,因此请确保不要在其存储大量数据。
  • AddNewRowToGrid():当单击Button时,向GridView添加新行的a方法,并将新添加的行值存储在SetInitialRow()方法中定义的原始表中。
  • SetPreviousData():一个在回发时保留从DropDownListTextBox选择的所有项的方法。
  • ResetRowID():在删除行时刷新网格行号的方法。

事件

  • ButtonAdd_ Click:调用AddNewRowToGrid()方法。 
  • LinkDelete_Click:当从网格中单击“删除”链接时,将调用此方法。这是根据行索引从数据源中删除数据,然后重置行号,最后再次将更新后的数据源存储在ViewState中并将其绑定到网格以反映更改的地方。
  • Gridview1_RowCreated:在这里,我们在GridView中放置了基本验证,以防止用户在最后一行看到“删除”按钮。

输出

运行页面后,浏览器将显示类似以下内容:

初始加载时

添加一些新行

删除一行

删除一行后

就是这样!现在大家可能会问的下一件事是如何将数据保存到数据库。放心,因为在下一步中我将向您展示如何操作。

一次性保存所有数据

首先要做的是创建数据库和用于存储数据的表。因此,启动SQL Management Studio或SQL Server的Express版本,并创建具有以下字段的表:

CREATE TABLE [dbo].[GridViewDynamicData](
    [RowID] [tinyint] IDENTITY(1,1) NOT NULL,
    [Field1] [varchar](50) NULL,
    [Field2] [varchar](50) NULL,
    [Field3] [varchar](50) NULL,
    [Field4] [varchar](50) NULL
) ON [PRIMARY]

GO

将表保存为您喜欢的名称,但在此演示中,我将表命名为“GridViewDynamicData”。

注意:我将RowID设置为自动增量,以便为表中每个新添加的行自动生成ID。为此,请选择“RowID”列名,并在列属性中将“Identity Specification”设置为yes。

创建表后,切换回Visual Studio并在表单上添加一个Button控件。

例如

<asp:Button ID="BtnSave" runat="server" Text="Save All" OnClick="BtnSave_Click" /> 

现在让我们创建将数据保存到数据库的方法。在这里,我们需要做的第一件事是设置连接字符串,以便我们的代码可以与数据库进行通信。在此示例中,我们将使用web.config文件来设置连接字符串。请参阅下面的标记:

<connectionStrings>  
   <add name="DBConnection" connectionString="Data Source=win-ehm93ap21cf\SQLEXPRESS;Initial Catalog=DemoDB;Integrated Security=SSPI;" providerName="System.Data.SqlClient"/>   
</connectionStrings>

注意:您可能需要更改Data SourceInitial Catalog的值。

现在我们可以继续创建将数据保存到数据库的方法。首先,在下方添加以下命名空间:

using System.Data;
using System.Data.SqlClient;

我们需要声明上面的命名空间,以便我们可以使用SqlClient、ADO.NET对象来处理数据。

其次,创建调用从web.config文件中设置的连接字符串的方法。

private string GetConnectionString()   
{  
   return ConfigurationManager.ConnectionStrings["DBConnection"].ConnectionString;  
}

这是将所有行插入数据库的代码块:

private void InsertRecords(DataTable source) {
            using (SqlConnection connection = new SqlConnection(GetConnectionString()))
            {
                using (SqlBulkCopy sqlBulkCopy = new SqlBulkCopy(connection))
                {
                    //Set the Database Table to use
                    sqlBulkCopy.DestinationTableName = "dbo.GridViewDynamicData";

                    //[OPTIONAL]: Mappings of columns from Datatable against Database table
                    sqlBulkCopy.ColumnMappings.Add("Field1", "Field1");
                    sqlBulkCopy.ColumnMappings.Add("Field2", "Field2");
                    sqlBulkCopy.ColumnMappings.Add("Field3", "Field3");
                    sqlBulkCopy.ColumnMappings.Add("Field4", "Field4");
                    connection.Open();
                    sqlBulkCopy.WriteToServer(source);
                }
            }

            lblMessage.Text = "Records successfully saved!";
}

InsertRecords()方法以DataTable对象作为参数。DataTable对象包含动态网格中的所有值。我们使用SqlBulkCopy.WriteToServer方法一次性将DataTable中的所有行加载到数据库的指定表名中。 

最后,这是Button点击事件的代码块:

protected void BtnSave_Click(object sender, EventArgs e) {
            if(Gridview1.Rows.Count > 0)
            {
                DataTable dt = new DataTable();
                dt.Columns.AddRange(new DataColumn[4] {
                    new DataColumn("Field1", typeof(string)),
                    new DataColumn("Field2", typeof(string)),
                    new DataColumn("Field3",typeof(string)),
                    new DataColumn("Field4",typeof(string))});

                foreach (GridViewRow row in Gridview1.Rows)
                {
                    string field1 = ((TextBox)row.Cells[1].FindControl("TextBox1")).Text;
                    string field2 = ((TextBox)row.Cells[2].FindControl("TextBox2")).Text;
                    string field3 = ((DropDownList)row.Cells[3].FindControl("DropDownList1")).SelectedItem.Text;
                    string field4 = ((DropDownList)row.Cells[4].FindControl("DropDownList2")).SelectedItem.Text;

                    dt.Rows.Add(field1, field2, field3, field4);
                }
                InsertRecords(dt);
            }
}

上面的代码非常直接。首先,我们创建了一个新的DataTable并定义了一些列定义,以便我们在此存储一些值。然后,我们遍历GridView中的行以提取控件值,然后将每个控件值添加到DataTable中。在添加完所有值后,我们调用InsertRecords()方法来实际执行数据库插入。

单击“Save All”按钮后,输出如下:

以下是存储在数据库中的捕获数据:

现在是奖励部分,如果您想验证每个TextBox中的空值,可以使用此JavaScript:

    <script>
        function ValidateEmptyValue() { 
            var gv = document.getElementById("<%= Gridview1.ClientID %>"); 
            var tb = gv.getElementsByTagName("input"); 
            
            for (var i = 0; i < tb.length; i++) { 
                if (tb[i].type == "text") { 
                    if (tb[i].value < 1) { 
                        alert("Field cannot be blank!"); 
                        return false; 
                    } 
                }   
            } 
            return true; 
        }
    </script>

然后,您可以像这样在ButtonAdd控件中调用JavaScript函数:

<asp:Button ID="ButtonAdd" runat="server" 
                Text="Add New Row" 
                onclick="ButtonAdd_Click"
                OnClientClick="return ValidateEmptyValue();" />

就是这样!希望您觉得这篇文章很有用。

我已将项目附加供您下载。玩得开心! 

摘要

在本文中,我们学习了如何在点击Button时在GridView中生成动态控件,并将所有数据一次性保存到数据库中。

© . All rights reserved.