当你使用GridView的时候,不要在page_load中绑定数据

本文指出在ASP.NET中常见的编程误区,即在Page_Load事件中直接从数据库加载数据到GridView控件,这种做法不仅效率低下还会引入逻辑错误。文章通过一个示例程序详细解释了正确的数据绑定方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在csdn我看到的一个很普遍的编程错误,就是在使用GridView时在page_load中从后台(数据库)绑定数据。实际上,那种写法是asp.net1.1时代我们不太懂asp.net,并且使用DataGrid等比较简单的控件时遗留的一种非常不成熟的写法,没想到现在在很多使用GridView编程的“范例”代码中还不断地影响初学者。这个写法错误地在每一次回发时在page_load中绑定数据,而这个方法中实际上应该是创建上一个页面输出html时的GridView控件树结构,而并不是应该去根据当前后台数据库的最新数据去创建GridView的控件树结构。因此,在page_load中绑定数据不但是大大降低程序运行效率的(因为重复读取后台数据),而且还有逻辑错误。如果要手写绑定代码,那么所有在回发后的绑定功能也应该是在page_load结束之后的某个事件中,而不应该在page_load中。

虽然我使用数据源控件,无需手写相关代码,因此可以确保流程正确。但是,为了给不使用数据源控件绑定数据而是手写代码像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> &nbsp;<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(); }



只是因为页面一创建,就有这个方法写好了,所以我们习惯上随便把代码塞在这个方法里。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值