虽然我使用数据源控件,无需手写相关代码,因此可以确保流程正确。但是,为了给不使用数据源控件绑定数据而是手写代码像GridView.DataSource属性传递数据的做法写一个Demo,我写了一个简化了的程序。(这里使用了.net2008的功能)
首先,在你的网站下创建一个cs文件来提供测试数据:
-
C# code
- using System.Collections.Generic; using System.Linq; static public class BLL { private static List<TestType> ret; static public IEnumerable<TestType> GetDatas(string cond1, string cond2) { if (ret == null) { ret = new List<TestType>(); for (int i = 0; i < 10; i++) { TestType x = new TestType { 申请人名 = "王海波" + i.ToString(), 审核人名 = "", 审核意见 = "" }; ret.Add(x); } } var result = ret.Where(c => true); if (cond1 != string.Empty) result = result.Where(c => c.审核意见.Contains(cond1)); if (cond2 != string.Empty) result = result.Where(c => c.审核人名 == cond2); return result; } static public void UpdateRet(string name, string a, string b) { TestType line = ret.Where(x => x.申请人名 == name).FirstOrDefault(); if (line != null) { line.审核意见 = a; line.审核人名 = b; } } } public class TestType { public string 申请人名 { get; set; } public string 审核意见 { get; set; } public string 审核人名 { get; set; } }
这里,业务对象是由TestType来简单定义的。BLL类有两个方法,用来查询和更新数据。我使用一个 List <TestType> 类型的静态数据集合来保存演示测试数据。实际使用时则往往只要将方法改为对后台数据库操作即可,接口时一样的。
而一个处理界面的aspx内容如下:
-
HTML code
- <%@ Page Language="C#" %> <script runat="server"> protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) this.GridView1.DataBind(); } protected void GridView1_DataBinding(object sender, EventArgs e) { this.GridView1.DataSource = BLL.GetDatas(this.TextBox1.Text.Trim(), this.TextBox2.Text.Trim()); } protected void GridView1_RowEditing(object sender, GridViewEditEventArgs e) { this.GridView1.EditIndex = e.NewEditIndex; this.GridView1.DataBind(); } protected void GridView1_RowCancelingEdit(object sender, GridViewCancelEditEventArgs e) { this.GridView1.EditIndex = -1; this.GridView1.DataBind(); } protected void Button1_Click(object sender, EventArgs e) { this.GridView1.DataBind(); } protected void 更新这一行(object sender, EventArgs e) { var bt = sender as LinkButton; var a = (bt.FindControl("Label1") as Label).Text; var b = (bt.FindControl("TextBox1") as TextBox).Text; var c = (bt.FindControl("TextBox2") as TextBox).Text; BLL.UpdateRet(a, b, c); this.GridView1.EditIndex = -1; this.GridView1.DataBind(); } private string[] _审核意见 = null; public string[] 审核意见 { get { if (_审核意见 == null) _审核意见 = new string[] { "", "同意", "不同意", "发回重审" }; return _审核意见; } } protected void 选择审核意见(object sender, EventArgs e) { var list = sender as DropDownList; var tb = list.FindControl("TextBox1") as TextBox; tb.Text = list.SelectedValue; } </script> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title></title> </head> <body> <form id="form1" runat="server"> 审核意见:<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox> <br /> 审核人:<asp:TextBox ID="TextBox2" runat="server"></asp:TextBox> <br /> <asp:Button ID="Button1" runat="server" Text="重新查询" OnClick="Button1_Click" /> <br /> <br /> <asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" OnDataBinding="GridView1_DataBinding" OnRowCancelingEdit="GridView1_RowCancelingEdit" OnRowEditing="GridView1_RowEditing"> <Columns> <asp:TemplateField HeaderText="申请人姓名" SortExpression="申请人名"> <EditItemTemplate> <asp:Label ID="Label1" runat="server" Text='<%# Eval("申请人名") %>'></asp:Label> </EditItemTemplate> <ItemTemplate> <asp:Label ID="Label1" runat="server" Text='<%# Bind("申请人名") %>'></asp:Label> </ItemTemplate> </asp:TemplateField> <asp:TemplateField HeaderText="审核意见" SortExpression="审核意见"> <EditItemTemplate> <asp:TextBox ID="TextBox1" runat="server" Text='<%# Bind("审核意见") %>'></asp:TextBox> <asp:DropDownList ID="DropDownList1" runat="server" DataSource="<%# this.审核意见 %>" AutoPostBack="true" OnSelectedIndexChanged="选择审核意见"> </asp:DropDownList> </EditItemTemplate> <ItemTemplate> <asp:Label ID="Label2" runat="server" Text='<%# Bind("审核意见") %>'></asp:Label> </ItemTemplate> </asp:TemplateField> <asp:TemplateField HeaderText="审核人名" SortExpression="审核人名"> <EditItemTemplate> <asp:TextBox ID="TextBox2" runat="server" Text='<%# Bind("审核人名") %>'></asp:TextBox> </EditItemTemplate> <ItemTemplate> <asp:Label ID="Label3" runat="server" Text='<%# Bind("审核人名") %>'></asp:Label> </ItemTemplate> </asp:TemplateField> <asp:TemplateField ShowHeader="False"> <EditItemTemplate> <asp:LinkButton ID="LinkButton1" runat="server" CausesValidation="True" Text="更新" OnClick="更新这一行"></asp:LinkButton> <asp:LinkButton ID="LinkButton2" runat="server" CausesValidation="False" CommandName="Cancel" Text="取消"></asp:LinkButton> </EditItemTemplate> <ItemTemplate> <asp:LinkButton ID="LinkButton1" runat="server" CausesValidation="False" CommandName="Edit" Text="编辑"></asp:LinkButton> </ItemTemplate> </asp:TemplateField> </Columns> </asp:GridView> <br /> <asp:Button ID="Button2" runat="server" Text="什么也不做,专用来测试随机回发时页面状态是否正常" /> </form> </body> </html>
在界面中,有两个查询条件,第一个用于输入过滤审核意见(包含某些文字),第二个用来过滤审核人姓名。
请注意,数据时如何、合适绑定的。如果你在 BLL.GetDatas 方法设置一个断点,观察一下,何时才会读取后台数据库值。例如,你可以对某一行,点击“编辑”,然后再DropdownList上选择某个一个审批意见,然后再点击页面最底部的“什么也不做,专用来测试随机回发”按钮,你会看到DroopdownList中的值的状态并不会丢失,而且此时 BLL.GetDatas 中的断点也不会执行(说明并不读取后台数据库值),而且你在“审核意见”的get方法的第一行设置断点调试可以看到此时并不会重新读取DropdownList的后台数据(这说明每一行中某列嵌入复杂控件此时也不会重新绑定)。
而开头说的那种错误写法,则是大量地重复读取后台数据用于重新绑定,不但速度及其慢,而且逻辑上也是有bug的(只是你在开发用的机器上没有什么并发操作,很难发现bug)。
实际上,我看到很多在page_load中有为GridView的DataSource设置从后台查询的数据集来绑定控件做法,不但初学者会如此,写“范例”代码的blog中也会有很多。这是一个相当普遍的编程错误。
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
this.GridView1.DataBind();
}
这个写法其实是我们的一个懒习惯。按照逻辑,此时放在PreRender中其实是更加合适的,既:
-
C# code
- protected void Page_PreRender(object sender, EventArgs e) { if (!IsPostBack) this.GridView1.DataBind(); }
只是因为页面一创建,就有这个方法写好了,所以我们习惯上随便把代码塞在这个方法里。