<1>Web窗体准备:
1,VS2017-->文件-->新建-->项目-->ASP.net空网站-->设置好项目名和文件保存的位置-->打开解决方案资源管理器-->右键项目名-->添加-->添加新项-->选择Web窗体-->确定。
[注]:使用ASP.net空网站的目的是没有其他框架过多的束缚,有利于调试核心的程序部分;Web窗体默认名为Default.aspx,可以改也可以不改。
2,打开Default.aspx,使用工具箱中控件或者元素标签,移到设计面板中。因为打开Default.aspx文件后,代码面板区左下角会有三个不同的选项:设计/拆分/源。最好使用拆分,这样设计的内容和源代码内容都可以同步看到。
下面是我的源代码,根据源代码来讲设计意图:
[注:]我使用了两个HTML的table元素标签,主要是用来装具体的响应控件,比如按钮,TextBox,Table(这个Table就是用来记录要存放到数据库中的多条数据)HTML的table元素跟Table控件是有区别的。GridView主要用于显示数据库表中的内容,以及每次插入之后
数据库的内容。
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default2.aspx.cs" Inherits="Default2" %> <%----%>
<%--替换成下面这句,是用于下面的table元素中的cellspacing,cellpadding属性,因为XHTML5中这连个不是table的属性--%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
这是布局后的样子:
<2>编写响应事件的代码
1,首先是Page_Load()函数,也就是第一次加载Default.aspx页面,所要做的事情。
protected void Page_Load(object sender, EventArgs e) { string constr = ConfigurationManager.ConnectionStrings["pubsConString"].ConnectionString; SqlConnection con = new SqlConnection(constr); SqlDataAdapter da = new SqlDataAdapter("select * from agent_bak",con); DataSet ds = new DataSet(); da.Fill(ds); GridView1.DataSource = ds; GridView1.DataBind(); if (Convert.ToInt16(ViewState["Count"])!= 0)//if 中的判断语句也可以写成ViewState["Count"]!=null { for (int i = 0; i < Convert.ToInt16(ViewState["Count"]); i++) { AddTextBox(); } } else { btnData.Enabled = false; } }
这个函数包含的内容有:
a,通过配置文件中的内容来设置数据库连接语句。
b,将数据库中具体表的内容显示到GridView控件中
c,使用ViewState(这个问题要跟后面的按钮响应事件联系起来后面再讲)
a,配置文件中的内容:
其中password为你的SQLserver数据库的密码,我的数据库名称为sales,里面有一个agent_bak表,表的字段情况为:
b,Page_Load()函数一运行,也就是用浏览器打开这个页面,就会将数据库sales中的agent_bak表中的所有内容显示在GridView控件上。
至于if else语句中的内容,要先将清后面的内容才能讲清。
2,编写AddTextBox()函数,用于记录要插入数据库的内容,这里设计的是一个Table控件,只要调用这个函数,那么这个Table控件就会新增一个单元格,而这个单元格里面就可以写入要存入数据库的记录。
public void AddTextBox() { //要插入的数据 TableRow tr = new TableRow(); TableCell c1 = new TableCell(); TextBox txt = new TextBox(); txt.ID = "tb" + Table1.Rows.Count; txt.Font.Size = FontUnit.Point(9); //提示信息 TableCell c2 = new TableCell(); Label lb = new Label(); lb.ID = "lb" + Table1.Rows.Count; lb.Width = 50; lb.Text = "数据" + (Table1.Rows.Count + 1); c2.Controls.Add(lb); c1.Controls.Add(txt); tr.Cells.Add(c2); tr.Cells.Add(c1); Table1.Rows.Add(tr); //Table-->tr-->Cells-->每个Cell }
3, 添加单元格响应事件:
protected void brnAddTxt_Click(object sender, EventArgs e) { AddTextBox(); ViewState["Count"] = Convert.ToInt16(ViewState["Count"]) + 1; btnData.Enabled = true; }
a,第一先把Table控件单元格画一个。
b,这里我就可以讲Page_Load()函数中的ViewState的意图:
我把ViewState理解成记录状态的一个字典。刚开始Page_Load()执行的时候ViewState["Count"]值为null,也就是Convert.ToInt16(ViewState["Count"])为0,那么Page_Load()的if中的语句不执行,else中的语句执行btnData.Enabled = false,那么现在一方面没有画出增加的单元格,另一方面也无法点击添加数据按钮。
当点击增加单元格按钮后,Table控件增加了一个单元格。Convert.ToInt16(ViewState["Count"])值增加一,如图:
这里因为点击控件按钮之后,那么会重新调用Page_Load()函数,那么GridView会更新获得数据库表中的内容。由于Convert.ToInt16(ViewState["Count"])=1,那么AddTextBox()会从新绘制,而不会因为重新刷新页面到时,这个新增的单元格消失掉,从而保证能写入数据。
写入数据之后,Table.Rows.Count就会加1。如果在点击添加单元格,Table控件再增加了一个单元格,那么Convert.ToInt16(ViewState["Count"])=2,我们按了按钮,肯定应该所有重新绘制,但是Page_Load()函数中有(ViewState["Count"]),这里调用两次AddTextBox(),就保证了能记录第二个数据。
这里我就体会了这个ViewState是多么巧妙,还有那个Table控件。每次记录时候,都会是记录在这个Table的新的行里,这就为后面循环插入数据库做了充分准备。
4,最后我们看看那个添加到数据库中的函数,也就是循环插入。这个函数比较麻烦的地方是写Insert语句中的引号问题。
protected void btnData_Click(object sender, EventArgs e) { string constr = ConfigurationManager.ConnectionStrings["pubsConString"].ConnectionString; SqlConnection con = new SqlConnection(constr); con.Open(); SqlCommand cmd; string cmdTxt; for (int i = 0; i < Table1.Rows.Count; i++) { string b = ""; string[] a = ((TextBox)Table1.Rows[i].FindControl("tb" + i)).Text.Split(','); for (int j = 0; j < a.Length - 1; j++) { b += "'" + a[j] + "'" + ","; } b += "'" + a[a.Length - 1] + "'"; //cmdTxt = "insert into agent_bak(aid,aname,city,per) values('" + ((TextBox)Table1.Rows[i].FindControl("tb" + i)).Text.ToString() + "')"; cmdTxt = "insert into agent_bak(aid,aname,city,per) values(" + b+ ")"; cmd = new SqlCommand(cmdTxt,con); cmd.ExecuteNonQuery(); } con.Close(); //Response.Write(""); }
到此结束。