GridView实战一:自定义分页、排序、修改、插入、删除
前言:
在某次公司面试时被问到对GridView操作的熟悉程度,在那之前一直用Repeater内嵌table标签对GridView操作确实很少,于是最近在项目的后台上对GridView进行了一番实操,本文和后面的另一篇GridView实战二:使用ObjectDataSource数据源控件均是这段时间的一些总结。
GridView优点就是集数据绑定、分页、排序、删、改于一身,提高了开发效率;缺点嘛,就是运行效率低,并且它本身不带添加功能。于是GridView用于后台开发是一个不错的选择,而前台页面还是少用为妙咯。
实战一:
1.本次实战效果图如下:
图一.展示状态
图二.编辑状态
图三.添加记录状态
2.具体代码
.aspx页面
1 <asp:GridView runat="server" ID="gv" AutoGenerateColumns="false"
2 AllowPaging="true" PageSize="1" AllowSorting="true" DataKeyNames="ID"
3 OnRowDataBound="gv_OnRowDataBound" OnRowDeleting="gv_OnRowDeleting"
4 OnRowEditing="gv_OnRowEditing" OnRowCancelingEdit="gv_OnRowCancelingEdit"
5 OnRowUpdating="gv_OnRowUpdating" OnSorting="gv_OnSorting">
6 <HeaderStyle BackColor="graytext" />
7 <Columns>
8 <asp:TemplateField>
9 <HeaderStyle Width="20%" />
10 <HeaderTemplate>
11 <asp:LinkButton runat="server" ID="lbtnSortName" Text="Name" CommandName="Sort" CommandArgument="Name">
12 </asp:LinkButton>
13 </HeaderTemplate>
14 <ItemTemplate><%#Eval("Name") %></ItemTemplate>
15 <EditItemTemplate>
16 <asp:TextBox runat="server" ID="tbxName" Text='<%#Eval("Name") %>'></asp:TextBox>
17 <asp:RegularExpressionValidator runat="server" ID="revName" ControlToValidate="tbxName"
18 ValidationExpression="[a-zA-Z]+" ErrorMessage="Please input your English name!" Display="Dynamic">
19 </asp:RegularExpressionValidator>
20 <asp:RequiredFieldValidator runat="server" ID="rfvName" ControlToValidate="tbxName"
21 ErrorMessage="Please input your name" Display="Dynamic">
22 </asp:RequiredFieldValidator>
23 </EditItemTemplate>
24 </asp:TemplateField>
25 <asp:TemplateField>
26 <HeaderStyle Width="10%"/>
27 <HeaderTemplate>
28 <asp:LinkButton runat="server" ID="lbtnSortSex" Text="Sex" CommandName="Sort" CommandArgument="Sex">
29 </asp:LinkButton>
30 </HeaderTemplate>
31 <ItemTemplate>
32 <asp:RadioButtonList Enabled="false" runat="server" ID="rblSexShow" RepeatDirection="Horizontal"
33 RepeatColumns="2">
34 </asp:RadioButtonList>
35 </ItemTemplate>
36 <EditItemTemplate>
37 <asp:RadioButtonList runat="server" ID="rblSexEdit" RepeatDirection="Horizontal" RepeatColumns="2">
38 </asp:RadioButtonList>
39 </EditItemTemplate>
40 </asp:TemplateField>
41 <asp:TemplateField>
42 <HeaderStyle Width="20%"/>
43 <HeaderTemplate>
44 <asp:LinkButton runat="server" ID="lbtnSortCountry" Text="Country" CommandName="Sort" CommandArgument="Country">
45 </asp:LinkButton>
46 </HeaderTemplate>
47 <ItemTemplate><%#Eval("Country")%></ItemTemplate>
48 <EditItemTemplate>
49 <asp:DropDownList runat="server" ID="ddlCountry"></asp:DropDownList>
50 </EditItemTemplate>
51 </asp:TemplateField>
52 <asp:TemplateField>
53 <HeaderStyle Width="20%"/>
54 <HeaderTemplate>Hobby</HeaderTemplate>
55 <ItemTemplate><%#Eval("Hobby") %></ItemTemplate>
56 <EditItemTemplate>
57 <asp:CheckBoxList runat="server" ID="cbxlHobby" RepeatDirection="Horizontal" RepeatColumns="5">
58 </asp:CheckBoxList>
59 </EditItemTemplate>
60 </asp:TemplateField>
61 <asp:TemplateField ItemStyle-HorizontalAlign="Center">
62 <HeaderStyle Width="10%"/>
63 <HeaderTemplate>
64 <asp:LinkButton runat="server" ID="lbtnShowAdd" Text="Add" OnClick="lbtnShowAdd_OnClick">
65 </asp:LinkButton>
66 </HeaderTemplate>
67 <ItemTemplate>
68 <asp:LinkButton runat="server" ID="lbtnEdit" Text="Edit" CommandName="Edit" /> 
69 <asp:LinkButton runat="server" ID="lbtnDelete" Text="Delete" CommandName="Delete" />
70 </ItemTemplate>
71 <EditItemTemplate>
72 <asp:LinkButton runat="server" ID="lbtnSubmit" Text="Update" CommandName="Update" /> 
73 <asp:LinkButton runat="server" ID="lbtnCancel" Text="Cancel" CommandName="Cancel" />
74 </EditItemTemplate>
75 </asp:TemplateField>
76 </Columns>
77 <PagerSettings Visible="true" />
78 <PagerStyle Font-Size="12px"/>
79 <PagerTemplate>
80 <div style="float:left;margin-left:15px;color:#999;line-height:20px">
81 当前第<%#this.gv.PageIndex+1 %>/<%#this.gv.PageCount %>页
82 </div>
83 <div style="float:right;margin-right:15px;color:#999;line-height:20px">页</div>
84 <div style="float:right">
85 <asp:DropDownList runat="server" ID="ddlPaging" AutoPostBack="true"
86 OnSelectedIndexChanged="ddlPaging_OnSelectedIndexChanged">
87 </asp:DropDownList>
88 </div>
89 <div style="float:right;color:#999;line-height:20px">跳转到第</div>
90 </PagerTemplate>
91 <EmptyDataTemplate>
92 <div><b>Name:</b>
93 <asp:TextBox runat="server" ID="tbxName"></asp:TextBox>
94 <asp:RegularExpressionValidator runat="server" ID="revName" ControlToValidate="tbxName"
95 ValidationExpression="^[a-zA-Z]+$" Display="Dynamic" ErrorMessage="Please input your English name!">
96 </asp:RegularExpressionValidator>
97 <asp:RequiredFieldValidator runat="server" ID="rfvName" ControlToValidate="tbxName"
98 ErrorMessage="Please input your name" Display="Dynamic">
99 </asp:RequiredFieldValidator>
100 </div>
101 <div><b>Sex:</b>
102 <asp:RadioButtonList runat="server" id="rblSex" RepeatColumns="2" RepeatDirection="Horizontal">
103 <asp:ListItem Value="M" Text="Male" Selected="True"></asp:ListItem>
104 <asp:ListItem Value="F" Text="Female"></asp:ListItem>
105 </asp:RadioButtonList>
106 </div>
107 <div><b>Country:</b>
108 <asp:DropDownList runat="server" ID="ddlCountry">
109 </asp:DropDownList>
110 <asp:RequiredFieldValidator runat="server" ID="rfCountry" ControlToValidate="ddlCountry"
111 ErrorMessage="Please Choose Country" Display="Dynamic">
112 </asp:RequiredFieldValidator>
113 </div>
114 <div><b>Hobby:</b>
115 <asp:CheckBoxList runat="server" ID="cbxlHobby" RepeatColumns="5" RepeatDirection="Horizontal">
116 </asp:CheckBoxList>
117 </div>
118 <div>
119 <asp:LinkButton runat="server" ID="lbtnSubmit" Text="Submit" OnClick="lbtnSubmit_OnClick" />
120 <asp:LinkButton runat="server" ID="lbtnCancel" Text="Cancel" OnClick="lbtnCancel_OnClick"
121 CausesValidation="false"/>
122 </div>
123 </EmptyDataTemplate>
124 </asp:GridView>
说明:
1.显示状态时:对于只显示文字串的用<%#Eval("字段名")%>直接绑定,而对于单选组(性别)的内容就放在GridView的OnRowDataBound来绑定。
2.编辑状态时:复选组、单选组合下拉列表都在OnRowDataBound来绑定;这里没有用数据源控件,所以用<%#Bind("字段名")%>和<%#Eval("字段名")%>没区别,<%#Bind("字段名")%>的双向通讯不起作用。
3.新增状态:因为GridView自身附带新增记录的功能,所以选择在EmptyDataTemplate中实现新增的功能(借鉴其他同行的做法!);因为使用了验证控件,所以把取消按钮(操作不验证合法性)设为不触发验证。
4.分页功能:本例是将分页功能放置到gridview的PagerTemplate中实现。这里有两个注意点:
a.DropDownList设置AutoPostBack为true;
b.因为要触发DropDownList的OnSelectedIndexChanged事件,所以viewstate要启用。触发OnSelectedIndexChanged事件的条件是postback的selectedIndex和原始值不同,当viewstate启用时原始值就是viewstate中保存的值,当viewstate禁用时就是控件初始化时的selectedIndex或第一个选项。因此如果禁用了ViewState那么当选择回控件初始化时的选项时就不会触发OnSelectedIndexChanged事件了。
c.GridView的OnRowDataBound中每次postback都重新初始化DropDownList。因为DropDownList包含在GridView中是动态生成的,当PostBack时GridView并不会恢复其中的动态内容;如果把分页功能放在GridView以外实现,那么动态生成的时DropDownList的选项,就Postback时不用再初始化了。
d.因为DropDownList位于GridView里面,所以当把某个ListItem的enable设为false时,该选项就不生成(连Html代码都没了),如果放在GridView外只是显示为不可用而已,原因不明。为实现添加状态初始画面中存在默认不可选的listitem效果,用了html的disabled属性来设置。
.aspx.cs代码
1 public partial class _Default : System.Web.UI.Page
3 private DataManager dm = new DataManager();
5 protected void Page_Load(object sender, EventArgs e)
6 {
7 if (!IsPostBack)
8 {
9 this.gv.DataSource = dm.GetDt();
10 this.gv.DataBind();
12 //记录最近一次排序方向
13 ViewState["Direction"] = SortDirection.Descending;
14 }
15 }
17 protected void gv_OnRowDataBound(object sender, GridViewRowEventArgs e)
18 {
19 DataRowView drv = e.Row.DataItem as DataRowView;
21 if (e.Row.RowType == DataControlRowType.DataRow)
22 {
23 //显示时
24 if (this.gv.EditIndex == -1)
25 {
26 //设置性别
27 RadioButtonList rbl = e.Row.FindControl("rblSexShow") as RadioButtonList;
28 rbl.Items.Add(new ListItem("Male", "M"));
29 rbl.Items.Add(new ListItem("Female", "F"));
30 if ((drv["Sex"] as string).ToLower().Equals("m"))
31 rbl.Items[0].Selected = true;
32 else
33 rbl.Items[1].Selected = true;
34 }
35 //修改时:
36 else if(e.Row.RowIndex == this.gv.EditIndex)
37 {
38 //性别
39 RadioButtonList rbl = e.Row.FindControl("rblSexEdit") as RadioButtonList;
40 rbl.Items.Add(new ListItem("Male", "M"));
41 rbl.Items.Add(new ListItem("Female", "F"));
42 if ((drv["Sex"] as string).ToLower().Equals("m"))
43 rbl.Items[0].Selected = true;
44 else
45 rbl.Items[1].Selected = true;
46 //国籍
47 DropDownList ddlCountry = e.Row.FindControl("ddlCountry") as DropDownList;
48 DataTable countryDt = dm.GetCountry();
49 ListItem li = null;
50 for(int i=0;i<countryDt.Rows.Count;++i)
51 {
52 string cn = countryDt.Rows[i]["cn"] as string;
53 li = new ListItem(cn, cn);
54 if (cn.Equals(drv["Country"] as string))
55 li.Selected = true;
56 ddlCountry.Items.Add(li);
57 }
58 //兴趣
59 CheckBoxList cbl = e.Row.FindControl("cbxlHobby") as CheckBoxList;
60 DataTable hobbyDt = dm.GetHobby();
61 string hobbys = drv["Hobby"] as string;
62 ListItem hobbyLi = null;
63 string hstr = string.Empty;
64 for (int i = 0; i < hobbyDt.Rows.Count; i++)
65 {
66 hstr = hobbyDt.Rows[i]["hobby"] as string;
67 hobbyLi = new ListItem(hstr, hstr);
68 if (hobbys.IndexOf(hstr)>=0)
69 hobbyLi.Selected = true;
70 cbl.Items.Add(hobbyLi);
71 }
72 }
73 }
74 else if (e.Row.RowType == DataControlRowType.Pager)
75 {
76 //绑定分页控件
77 DropDownList ddlPaging = e.Row.FindControl("ddlPaging") as DropDownList;
78 for (int i = 0; i < this.gv.PageCount; i++)
79 {
80 ddlPaging.Items.Add(new ListItem(Convert.ToString(i + 1), Convert.ToString(i)));
81 }
82 ddlPaging.SelectedIndex = this.gv.PageIndex;
83 }
84 else if (e.Row.RowType == DataControlRowType.EmptyDataRow)
85 {
86 //添加记录画面
87 //国籍
88 DropDownList ddlCountry = e.Row.FindControl("ddlCountry") as DropDownList;
89 DataTable countryDt = dm.GetCountry();
90 ListItem li = new ListItem("Please Select","");
91 li.Attributes["disabled"] = "disabled";
92 li.Selected = true;
93 ddlCountry.Items.Add(li);
94 for (int i = 0; i < countryDt.Rows.Count; ++i)
95 {
96 string cn = countryDt.Rows[i]["cn"] as string;
97 li = new ListItem(cn, cn);
98 ddlCountry.Items.Add(li);
99 }
100 //兴趣
101 CheckBoxList cbl = e.Row.FindControl("cbxlHobby") as CheckBoxList;
102 DataTable hobbyDt = dm.GetHobby();
103 ListItem hobbyLi = null;
104 string hstr = string.Empty;
105 for (int i = 0; i < hobbyDt.Rows.Count; i++)
106 {
107 hstr = hobbyDt.Rows[i]["hobby"] as string;
108 hobbyLi = new ListItem(hstr, hstr);
109 cbl.Items.Add(hobbyLi);
110 }
111 }
112 }
114 /// <summary>
115 /// 分页控件的OnSelectedIndexChanged
116 /// </summary>
117 /// <param name="sender"></param>
118 /// <param name="e"></param>
119 protected void ddlPaging_OnSelectedIndexChanged(object sender, EventArgs e)
120 {
121 this.gv.PageIndex = (sender as DropDownList).SelectedIndex;
122 this.gv.DataSource = dm.GetDt();
123 this.gv.DataBind();
124 }
126 /// <summary>
127 /// 删除记录
128 /// </summary>
129 /// <param name="sender"></param>
130 /// <param name="e"></param>
131 protected void gv_OnRowDeleting(object sender, GridViewDeleteEventArgs e)
132 {
133 dm.DelRecord(Convert.ToInt32(this.gv.DataKeys[e.RowIndex].Value));
134 this.gv.PageIndex = 0;
135 this.gv.DataSource = dm.GetDt();
136 this.gv.DataBind();
137 }
139 /// <summary>
140 /// 修改记录
141 /// </summary>
142 /// <param name="sender"></param>
143 /// <param name="e"></param>
144 protected void gv_OnRowEditing(object sender, GridViewEditEventArgs e)
145 {
146 this.gv.EditIndex = e.NewEditIndex;
147 this.gv.DataSource = dm.GetDt();
148 this.gv.DataBind();
149 }
151 /// <summary>
152 /// 取消修改
153 /// </summary>
154 /// <param name="sender"></param>
155 /// <param name="e"></param>
156 protected void gv_OnRowCancelingEdit(object sender, GridViewCancelEditEventArgs e)
157 {
158 this.gv.EditIndex = -1;
159 this.gv.DataSource = dm.GetDt();
160 this.gv.DataBind();
161 }
163 /// <summary>
164 /// 更新记录
165 /// </summary>
166 /// <param name="sender"></param>
167 /// <param name="e"></param>
168 protected void gv_OnRowUpdating(object sender, GridViewUpdateEventArgs e)
169 {
170 GridViewRow gvr = this.gv.Rows[e.RowIndex];
171 int id = Convert.ToInt32(this.gv.DataKeys[e.RowIndex].Value);
172 string name = (gvr.Cells[0].FindControl("tbxName") as TextBox).Text;
173 string sex = (gvr.Cells[1].FindControl("rblSexEdit") as RadioButtonList).SelectedValue;
174 string country = (gvr.Cells[2].FindControl("ddlCountry") as DropDownList).SelectedValue;
175 System.Text.StringBuilder hobbys = new System.Text.StringBuilder();
176 foreach (ListItem li in (gvr.Cells[3].FindControl("cbxlHobby") as CheckBoxList).Items)
177 {
178 if (li.Selected)
179 hobbys.Append(li.Value+",");
180 }
181 if (hobbys.Length >= 2)
182 hobbys.Remove(hobbys.Length - 1, 1);
183 dm.UpdateRecord(id, name, country, sex, hobbys.ToString());
185 this.gv.EditIndex = -1;
186 this.gv.DataSource = dm.GetDt();
187 this.gv.DataBind();
188 }
190 /// <summary>
191 /// 提交新记录
192 /// </summary>
193 /// <param name="sender"></param>
194 /// <param name="e"></param>
195 protected void lbtnSubmit_OnClick(object sender, EventArgs e)
196 {
197 LinkButton lbtnSubmit = sender as LinkButton;
198 GridViewRow tr = lbtnSubmit.NamingContainer as GridViewRow;
199 string name = (tr.Cells[0].FindControl("tbxName") as TextBox).Text;
200 string sex = (tr.Cells[0].FindControl("rblSex") as RadioButtonList).SelectedValue;
201 string country = (tr.Cells[0].FindControl("ddlCountry") as DropDownList).SelectedValue;
202 System.Text.StringBuilder hobbys = new System.Text.StringBuilder();
203 foreach (ListItem li in (tr.Cells[0].FindControl("cbxlHobby") as CheckBoxList).Items)
204 {
205 if (li.Selected)
206 hobbys.Append(li.Value + ",");
207 }
208 if (hobbys.Length >= 2)
209 hobbys.Remove(hobbys.Length - 1, 1);
210 dm.AddRecord(name,country,sex,hobbys.ToString());
212 this.gv.PageIndex = 0;
213 this.gv.DataSource = dm.GetDt();
214 this.gv.DataBind();
215 }
217 /// <summary>
218 /// 退出添加新记录
219 /// </summary>
220 /// <param name="sender"></param>
221 /// <param name="e"></param>
222 protected void lbtnCancel_OnClick(object sender, EventArgs e)
223 {
224 this.gv.DataSource = dm.GetDt();
225 this.gv.DataBind();
226 }
228 /// <summary>
229 /// 显示添加画面
230 /// </summary>
231 /// <param name="sender"></param>
232 /// <param name="e"></param>
233 protected void lbtnShowAdd_OnClick(object sender, EventArgs e)
234 {
235 this.gv.DataSource = null;
236 this.gv.DataBind();
237 }
239 /// <summary>
240 /// 排序
241 /// </summary>
242 /// <param name="sender"></param>
243 /// <param name="e"></param>
244 protected void gv_OnSorting(object sender, GridViewSortEventArgs e)
245 {
246 DataTable dt = dm.GetDt();
247 string direction = string.Empty;
248 if (e.SortDirection == (SortDirection)Enum.Parse(typeof(SortDirection),Convert.ToString(ViewState["Direction"])))
249 direction = "asc";
250 else
251 direction = "desc";
252 dt.DefaultView.Sort = string.Format("{0} {1}", e.SortExpression, direction);
253 ViewState["Direction"] = (direction.Equals("asc") ? SortDirection.Descending : SortDirection.Ascending);
254 this.gv.DataSource = dt;
255 this.gv.DataBind();
256 }
257 }
说明:
1.显示、编辑、新增时数据绑定都集中在gv_OnRowDataBound方法中,通过e.Row.RowType来分别处理。
2.排序:通过DataTable.DefaultView来实现,用一个ViewState变量存放最近一次的排序方向的反方向,来使每次排序的方向都不同。GridView的SortDirection为只读属性,所以别指望设定它来实现排序哦!
3.modify、update、delete和cancel按钮的实现利用GridView预设的CommandName来处理
CommandName 值 |
说明 |
---|---|
“Cancel” |
取消编辑操作并将 GridView 控件返回为只读模式。引发 RowCancelingEdit 事件。 |
“Delete” |
删除当前记录。引发 RowDeleting 和 RowDeleted 事件。 |
“Edit” |
将当前记录置于编辑模式。引发 RowEditing 事件。 |
“Page” |
执行分页操作。将按钮的 CommandArgument 属性设置为“First”、“Last”、“Next”、“Prev”或页码,以指定要执行的分页操作类型。引发 PageIndexChanging 和 PageIndexChanged 事件。 |
“Select” |
选择当前记录。引发 SelectedIndexChanging 和 SelectedIndexChanged 事件。 |
“Sort” |
对 GridView 控件进行排序。引发 Sorting 和 Sorted 事件。 |
“Update” |
更新数据源中的当前记录。引发 RowUpdating 和 RowUpdated 事件。 |
当然也可以自己写OnCommand的处理代码来处理,就是烦一点。
数据操作类:
1 public class DataManager
3 private static DataTable dt = null;//用户记录
4 private static DataTable countryDt = null;//国籍
5 private static DataTable hobbyDt = null;//兴趣
7 public DataManager()
8 {
9 if (dt == null)
10 {
11 dt = new DataTable();
12 dt.Columns.Add("ID");
13 dt.Columns.Add("Name");
14 dt.Columns.Add("Sex");
15 dt.Columns.Add("Country");
16 dt.Columns.Add("Hobby");
18 //Default Data
19 dt.Rows.Add(new object[] { 1,"Mary","F","China","Cooking,Music"});
20 dt.Rows.Add(new object[] { 2, "John", "M", "China", "Tennis" });
21 }
23 if (countryDt == null)
24 {
25 countryDt=new DataTable();
26 countryDt.Columns.Add("cn");
28 //Default Data
29 countryDt.Rows.Add(new object[] { "China" });
30 countryDt.Rows.Add(new object[] { "French" });
31 countryDt.Rows.Add(new object[] { "America" });
32 countryDt.Rows.Add(new object[] { "Afria" });
33 countryDt.Rows.Add(new object[] { "Japan" });
34 }
36 if (hobbyDt == null)
37 {
38 hobbyDt = new DataTable();
39 hobbyDt.Columns.Add("hobby");
41 //Default Data
42 hobbyDt.Rows.Add(new object[] { "Cooking" });
43 hobbyDt.Rows.Add(new object[] { "Music" });
44 hobbyDt.Rows.Add(new object[] { "Reading" });
45 hobbyDt.Rows.Add(new object[] { "Movies" });
46 hobbyDt.Rows.Add(new object[] { "Tennis" });
47 }
48 }
50 public DataTable GetDt()
51 {
52 return dt;
53 }
55 public bool DelRecord(int id)
56 {
57 DataRow[] drs = dt.Select("ID=" + id);
58 bool result = false;
59 if (drs.Length == 1)
60 {
61 dt.Rows.Remove(drs[0]);
62 result = true;
63 }
65 return result;
66 }
68 public bool UpdateRecord(int id, string name, string country, string sex, string hobby)
69 {
70 DataRow[] drs = dt.Select("ID=" + id);
71 bool result = false;
72 if (drs.Length == 1)
73 {
74 drs[0]["Name"] = name;
75 drs[0]["Country"] = country;
76 drs[0]["Hobby"] = hobby;
77 drs[0]["Sex"] = sex;
78 result = true;
79 }
81 return result;
82 }
84 public bool AddRecord(string name, string country, string sex, string hobby)
85 {
86 DataRow[] drs = dt.Select();
87 Array.Sort<DataRow>(drs, new Comparison<DataRow>(SortHandler));
88 int newId = 1+Convert.ToInt32(drs[0]["ID"]);
89 dt.Rows.Add(new object[] {newId,name,sex,country,hobby });
91 return true;
92 }
94 private int SortHandler(DataRow arg1, DataRow arg2)
95 {
96 if (Convert.ToInt32(arg1["ID"]) == Convert.ToInt32(arg2["ID"]))
97 return 0;
98 else if (Convert.ToInt32(arg1["ID"]) < Convert.ToInt32(arg2["ID"]))
99 return 1;
100 else
101 return -1;
102 }
104 public DataTable GetCountry()
105 {
106 return countryDt;
107 }