前言:
ObjectDataSource数据源控件优点甚多,确实令人爱不惜手,但不支持重绑定这一项确实让人失望。下面的实战二将通过ObjectDataSource配合GridView来实现删、改、分页、排序,并分析使用cache后排序失灵的原因。
实战:
1.效果:

图1.显示状态

图2.编辑状态
2.代码:
.aspx
1 <asp:ObjectDataSource runat="server" ID="ods" EnablePaging="true" TypeName="OdsDataManager"2 SelectCountMethod="GetRecordCount" SelectMethod="GetRecord" UpdateMethod="UpdateRecord"3 DeleteMethod="DelRecord" OnUpdating="ods_OnUpdating" SortParameterName="sortExpression">5 </asp:ObjectDataSource>6 <asp:GridView runat="server" ID="gv" DataSourceID="ods" AutoGenerateColumns="false"7 AllowPaging="true" PageSize="1" AllowSorting="true" DataKeyNames="ID"8 OnRowDataBound="gv_OnRowDataBound">9 <HeaderStyle BackColor="graytext" />10 <Columns>11 <asp:TemplateField>12 <HeaderStyle Width="20%" />13 <HeaderTemplate>14 <asp:LinkButton runat="server" ID="lbtnSortName" Text="Name" CommandName="Sort" CommandArgument="Name">15 </asp:LinkButton>16 </HeaderTemplate>17 <ItemTemplate><%#Eval("Name") %></ItemTemplate>18 <EditItemTemplate>19 <asp:TextBox runat="server" ID="tbxName" Text='<%#Bind("Name") %>'></asp:TextBox>20 <asp:RegularExpressionValidator runat="server" ID="revName" ControlToValidate="tbxName"21 ValidationExpression="[a-zA-Z]+" ErrorMessage="Please input your English name!" Display="Dynamic">22 </asp:RegularExpressionValidator>23 <asp:RequiredFieldValidator runat="server" ID="rfvName" ControlToValidate="tbxName"24 ErrorMessage="Please input your name" Display="Dynamic">25 </asp:RequiredFieldValidator>26 </EditItemTemplate>27 </asp:TemplateField>28 <asp:TemplateField>29 <HeaderStyle Width="10%"/>30 <HeaderTemplate>31 <asp:LinkButton runat="server" ID="lbtnSortSex" Text="Sex" CommandName="Sort" CommandArgument="Sex">32 </asp:LinkButton>33 </HeaderTemplate>34 <ItemTemplate>35 <asp:RadioButtonList Enabled="false" runat="server" ID="rblSexShow" RepeatDirection="Horizontal"36 RepeatColumns="2">37 </asp:RadioButtonList>38 </ItemTemplate>39 <EditItemTemplate>40 <asp:RadioButtonList runat="server" ID="rblSexEdit" RepeatDirection="Horizontal" RepeatColumns="2">41 </asp:RadioButtonList>42 </EditItemTemplate>43 </asp:TemplateField>44 <asp:TemplateField>45 <HeaderStyle Width="20%"/>46 <HeaderTemplate>47 <asp:LinkButton runat="server" ID="lbtnSortCountry" Text="Country" CommandName="Sort" CommandArgument="Country">48 </asp:LinkButton>49 </HeaderTemplate>50 <ItemTemplate><%#Eval("Country")%></ItemTemplate>51 <EditItemTemplate>52 <asp:DropDownList runat="server" ID="ddlCountry"></asp:DropDownList>53 </EditItemTemplate>54 </asp:TemplateField>55 <asp:TemplateField>56 <HeaderStyle Width="20%"/>57 <HeaderTemplate>Hobby</HeaderTemplate>58 <ItemTemplate><%#Eval("Hobby") %></ItemTemplate>59 <EditItemTemplate>60 <asp:CheckBoxList runat="server" ID="cbxlHobby" RepeatDirection="Horizontal" RepeatColumns="5">61 </asp:CheckBoxList>62 </EditItemTemplate>63 </asp:TemplateField>64 <asp:CommandField ShowDeleteButton="true" DeleteText="Delete" ShowEditButton="true" EditText="Edit" />65 </Columns>66 <PagerSettings Visible="true" />67 <PagerStyle Font-Size="12px"/>68 <PagerTemplate>69 <div style="float:left;margin-left:15px;color:#999;line-height:20px">70 当前第<%#this.gv.PageIndex+1 %>/<%#this.gv.PageCount %>页71 </div>72 <div style="float:right;margin-right:15px;color:#999;line-height:20px">页</div>73 <div style="float:right">74 <asp:DropDownList runat="server" ID="ddlPaging" AutoPostBack="true"75 OnSelectedIndexChanged="ddlPaging_OnSelectedIndexChanged">76 </asp:DropDownList>77 </div>78 <div style="float:right;color:#999;line-height:20px">跳转到第</div>79 </PagerTemplate>80 </asp:GridView>说明:
1.因用了数据源控件,所以Name在编辑状态时使用<%#Bind("Name")%>来实现双向通讯的绑定
2.因为没有添加的功能,所以用了asp:CommandField来实现编辑、删除等按钮的功能。
3.排序功能上只要在ods上设定SortParameterName,它的值就是SelectMethod中关于排序的参数的名称,然后设定GridView的AllowSorting为true就ok了。排序按钮上依然用到GridView内置的CommandName——Sort,然后CommandArgument设为要排序的字段名,至于排序的方向由ObjectDataSource负责,省心多了。
.aspx.cs代码
1 public partial class Default2 : System.Web.UI.Page2 {3 private OdsDataManager dm = new OdsDataManager();45 protected void Page_Load(object sender, EventArgs e)6 {78 }910 protected void gv_OnRowDataBound(object sender, GridViewRowEventArgs e)11 {12 DataRowView drv = e.Row.DataItem as DataRowView;1314 if (e.Row.RowType == DataControlRowType.DataRow)15 {16 //显示时17 if (this.gv.EditIndex == -1)18 {19 //设置性别20 RadioButtonList rbl = e.Row.FindControl("rblSexShow") as RadioButtonList;21 rbl.Items.Add(new ListItem("Male", "M"));22 rbl.Items.Add(new ListItem("Female", "F"));23 if ((drv["Sex"] as string).ToLower().Equals("m"))24 rbl.Items[0].Selected = true;25 else26 rbl.Items[1].Selected = true;27 }28 //修改时:29 else if (e.Row.RowIndex == this.gv.EditIndex)30 {31 //性别32 RadioButtonList rbl = e.Row.FindControl("rblSexEdit") as RadioButtonList;33 rbl.Items.Add(new ListItem("Male", "M"));34 rbl.Items.Add(new ListItem("Female", "F"));35 if ((drv["Sex"] as string).ToLower().Equals("m"))36 rbl.Items[0].Selected = true;37 else38 rbl.Items[1].Selected = true;39 //国籍40 DropDownList ddlCountry = e.Row.FindControl("ddlCountry") as DropDownList;41 DataTable countryDt = dm.GetCountry();42 ListItem li = null;43 for (int i = 0; i < countryDt.Rows.Count; ++i)44 {45 string cn = countryDt.Rows[i]["cn"] as string;46 li = new ListItem(cn, cn);47 if (cn.Equals(drv["Country"] as string))48 li.Selected = true;49 ddlCountry.Items.Add(li);50 }51 //兴趣52 CheckBoxList cbl = e.Row.FindControl("cbxlHobby") as CheckBoxList;53 DataTable hobbyDt = dm.GetHobby();54 string hobbys = drv["Hobby"] as string;55 ListItem hobbyLi = null;56 string hstr = string.Empty;57 for (int i = 0; i < hobbyDt.Rows.Count; i++)58 {59 hstr = hobbyDt.Rows[i]["hobby"] as string;60 hobbyLi = new ListItem(hstr, hstr);61 if (hobbys.IndexOf(hstr) >= 0)62 hobbyLi.Selected = true;63 cbl.Items.Add(hobbyLi);64 }65 }66 }67 else if (e.Row.RowType == DataControlRowType.Pager)68 {69 //绑定分页控件70 DropDownList ddlPaging = e.Row.FindControl("ddlPaging") as DropDownList;71 for (int i = 0; i < this.gv.PageCount; i++)72 {73 ddlPaging.Items.Add(new ListItem(Convert.ToString(i + 1), Convert.ToString(i)));74 }75 ddlPaging.SelectedIndex = this.gv.PageIndex;76 }77 }7879 /// <summary>80 /// 分页控件的OnSelectedIndexChanged81 /// </summary>82 /// <param name="sender"></param>83 /// <param name="e"></param>84 protected void ddlPaging_OnSelectedIndexChanged(object sender, EventArgs e)85 {86 this.gv.PageIndex = (sender as DropDownList).SelectedIndex;87 }8889 protected void ods_OnUpdating(object sender, ObjectDataSourceMethodEventArgs e)90 {91 string Sex = (this.gv.Rows[this.gv.EditIndex].FindControl("rblSexEdit") as RadioButtonList).SelectedValue;92 string Country = (this.gv.Rows[this.gv.EditIndex].FindControl("ddlCountry") as DropDownList).SelectedValue;93 System.Text.StringBuilder hobbys = new System.Text.StringBuilder();94 foreach (ListItem li in (this.gv.Rows[this.gv.EditIndex].FindControl("cbxlHobby") as CheckBoxList).Items)95 {96 if (li.Selected)97 hobbys.Append(li.Value+",");98 }99 if (hobbys.Length >= 2)100 hobbys.Remove(hobbys.Length - 1, 1);101102 e.InputParameters.Add("Sex", Sex);103 e.InputParameters.Add("Country", Country);104 e.InputParameters.Add("Hobby",hobbys.ToString());105 }106 }说明:
1.看到behind code是不是发现代码量少了很多呢?这就是用ods的好处了。
2.在更新操作时,因为Country、Sex和Hobby都没有和ods作双向绑定,所以要自己获取并写入到ods的InputParameters中,然后ods就会调用已经设置好的UpdateMethod了。
数据操作类
1 public class OdsDataManager2 {3 private static DataTable dt = null;//用户记录4 private static DataTable countryDt = null;//国籍5 private static DataTable hobbyDt = null;//兴趣67 public OdsDataManager()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");1718 //Default Data19 dt.Rows.Add(new object[] { 1, "Mary", "F", "China", "Cooking,Music" });20 dt.Rows.Add(new object[] { 2, "John", "M", "China", "Tennis" });21 }2223 if (countryDt == null)24 {25 countryDt = new DataTable();26 countryDt.Columns.Add("cn");2728 //Default Data29 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 }3536 if (hobbyDt == null)37 {38 hobbyDt = new DataTable();39 hobbyDt.Columns.Add("hobby");4041 //Default Data42 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 }4950 public DataTable GetRecord(int maximumRows, int startRowIndex, string sortExpression)51 {52 //排序53 if(!string.IsNullOrEmpty(sortExpression))54 {55 dt.DefaultView.Sort = sortExpression;56 }5758 DataRow[] drs = dt.Select();59 DataTable dt1 = dt.Clone();60 for (int i = startRowIndex; i < startRowIndex+maximumRows && i<drs.Length; i++)61 {62 dt1.Rows.Add(drs[i].ItemArray);63 }6465 return dt1;66 }6768 public int GetRecordCount()69 {70 return dt.Rows.Count;71 }7273 public bool UpdateRecord(int ID, string Name, string Sex, string Country, string Hobby)74 {75 bool result = false;76 DataRow[] drs = dt.Select("ID=" + ID);77 if (drs.Length == 1)78 {79 drs[0]["Name"] = Name;80 drs[0]["Sex"] = Sex;81 drs[0]["Country"] = Country;82 drs[0]["Hobby"] = Hobby;8384 result = true;85 }8687 return result;88 }8990 public bool DelRecord(int ID)91 {92 bool result = false;93 DataRow[] drs = dt.Select("ID=" + ID);94 if (drs.Length == 1)95 {96 dt.Rows.Remove(drs[0]);9798 result = true;99 }100101 return result;102 }103104 public DataTable GetCountry()105 {106 return countryDt;107 }108109 public DataTable GetHobby()110 {111 return hobbyDt;112 }113 }说明:
1.GetRecord方法绑定到ods的SelectMethod上,因为启用分页和排序功能,所以参数数组中必须有maximumRows(每页记录数), startRowIndex(当前页首条记录在整个数据集中的索引), sortExpression(排序表达式,首次加载页面时为空字符串,postback时含排序字段和排序方向)。
3.数据缓存
ods可以启用cache,该cache为应用程序级的,就是多个画面的ods只要SelectMethod和SelectCountMethod、Select参数一样就可以共享缓存中的数据,在Cache有效时进行Select操作将会先根据前面说的三个要素从Cache中获取数据,如果没有才执行SelectMethod方法。注意不同的要素组合会各自对应一份缓存的数据,当第二次请求时就直接读缓存。
就是因为这样问题就来了,如果启用了cache那么上面的排序功能就会失效,而其他功能依然正常。原因在于排序操作是在SelectMethod中实现,而在Cache生效时程序根本就不执行SelectMethod方法,除非说内存不足或其他原因令cache不够大来保存数据而被迫执行SelectMethod方法。对于该问题目前还没找到解决的方法,望大哥们来告诉我啦^_^
好消息:对于上面的问题终于找到了解决方法,就是自定义一个缓存层而不使用ods附带的缓存功能。
欢迎添加我的公众号一起深入探讨技术手艺人的那些事!










