2012-07-23

[ASP.NET]GridView自已動手寫排序

GridView有內建的排序功能,使用起來非常的簡單,幾乎不用寫到什麼程式就能有排序的效果了,而它底層的執行方式其實就是拿你第一次BindData時的SQL語法來做order by而己。

但是當你的Gridview顯示出來的欄位並非一次就能用一個SQL完全抓出來,必須在RowDataBound再處理過、甚至再次下SQL抓取時,就無法使用內建的排序功能了,因為當它使用第一次BindData時的SQL去做order by時,會因為找不到那個另外處理的欄位而報錯,這時只能自已來處理排序功能了。

其實手動自已做的排序功能的流程大致都跟使用內建的流程一樣,也是先開啟GridView的AllowSorting以及GridView_Sorting()函式,差別就在於要在GridView_Sorting()函式中自已把現在GridView的所有資料暫存下來,做好排序後再重新BindDate給GridView。而在此要示範的是用List<obj>來暫存資料,因為它有內建的linq排序函式OrderByDescending()跟OrderBy()。

首先可以在Page_Load()加個ViewState記錄排序的升冪或降冪:
protected void Page_Load(object sender, EventArgs e)
{
     ...
     if (!IsPostBack) ViewState["sort"] = "asc";
     ...
}

再來是GridView_Sorting()的寫法:
protected void GridView_Sorting(object sender, GridViewSortEventArgs e)
{
     //暫存現有GridView的資料
     List<obj> lts = GetCurrentGridView();

     //判斷先前是升冪或降冪, 這次就要相反排
     if (ViewState["sort"].ToString() == "asc")
     {
         lts = lts.OrderByDescending(p => GetPropertyValue(p, e.SortExpression)).ToList();
         ViewState["sort"] = "desc";
     }
     else
     {
         lts = lts.OrderBy(p => GetPropertyValue(p, e.SortExpression)).ToList();
         ViewState["sort"] = "asc";
     }

     //重新BindDate
     BindView(lts);
}

//使用反射,根據屬性的型別找出屬性的內容值
public static object GetPropertyValue(object obj, string property)
{
     System.Reflection.PropertyInfo propertyInfo = obj.GetType().GetProperty(property);
     return propertyInfo.GetValue(obj, null);
}

private List<obj> GetCurrentGridView()
{
     List<obj> list = new List<obj>();

     for (int i = 0; i < gv.Rows.Count; i++)
     {
         obj o = new obj();

         o.lbl1 = ((Label)gv.Rows[i].FindControl("lbl1")).Text;
         o.lbl2 = ((Label)gv.Rows[i].FindControl("lbl2")).Text;
         o.lbl3 = ((Label)gv.Rows[i].FindControl("lbl3")).Text;

         list.Add(o);
     }

     return list;
}

private void BindView(List<obj> list)
{
     gv.DataSource = list;
     gv.DataBind();
}

沒有留言:

張貼留言