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






4.43/5 (4投票s)
一个简单的演示,展示如何使用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
会自动生成一行TextBoxes
和DropDownLists
。您还会看到我在最后一个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()
:一个在回发时保留从DropDownList
和TextBox
选择的所有项的方法。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 Source
和Initial 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中生成动态控件,并将所有数据一次性保存到数据库中。