2010年11月7日 星期日

ASP.Net GridView 的自訂資料繫結

在論壇上,常常看到有網友提出這樣的問題:如果資料值是 Y/N,要顯示 是/否 在 GridView 上,要如何做?
這個問題有幾種解法

第一種:使用 GridView.RowDataBound 事件,搭配 TemplateField

這種方法是大部分的書上會介紹的方法

RowDataBound 事件,會傳入一個型別為 GridViewRowEventArgs 的參數 e
e.Row 指的是 GridView 剛剛做完資料繫結的列
e.Row.DataItem 指的是用來做這個列的資料繫結的資料來源,型別是 object
如果以 DataTable 或是 DataSet 做資料來源,e.Row.DataItem 實際上是一個 DataRowView
所以,如果以 DataTable 或是 DataSet 做資料來源,(e.Row.DataItem as DataRowView).Row["欄位名稱"] 可以取得欄位的資料值

接下來,就是「數格子」,要知道你的 TemplateField 是第幾欄,還要知道要做自訂資料繫結的控制項是 ItemTemplate 的第幾個控制項


(e.Row.Cells[欄索引].Controls[控制項索引] as 控制項型別).Text =
  (e.Row.DataItem as DataRowView).Row["欄位名稱"].ToString()

或是要知道自訂資料繫結的控制項的 ID

(e.Row.Cells[欄索引].FindControl("控制項ID") as 控制項型別).Text =
  (e.Row.DataItem as DataRowView).Row["欄位名稱"].ToString()

這種方法的缺點是
  1. 如果在這個TemplateField 之前,加入或是刪掉了其他欄,或是修改了 TemplateField 的 ItemTemplate,事件處理都得修改
  2. 如果不是以 DataTable 或是 DataSet 做資料來源,e.Row.DataItem 事實上是什麼型別?

不確定因素太多,既麻煩又複雜!強烈不建議使用這個方法

第二種:使用單純自訂資料繫結,搭配 TemplateField
這種方法直接在 TemplateField 的 ItemTemplate 中放置一個 Label,並設置 Text 屬性的資料繫結為

Text='<%# Eval("欄位名稱").ToString() == "Y" ? "是" : (Eval("欄位名稱").ToString() == "N" ? "否" : "") %>'
Text='<%# Eval("欄位名稱", "{0}") == "Y" ? "是" : (Eval("欄位名稱", "{0}") == "N" ? "否" : "") %>'

簡單明瞭,只是判斷是寫在 .aspx 裡面,而且當資料值是 DbNull 的時候會發生錯誤,如果還要加上判斷是否為 DbNull 的語法就更複雜了
因此,此方法建議使用於簡單判斷以及資料欄位不允許 null 的狀況
PS: Eval("欄位名稱") 與 Eval("欄位名稱", "{0}") 的不同點在於前者回傳的是 Object,後者回傳的是 String

第三種:使用自訂資料繫結方法,搭配 TemplateField
跟第二種方法類似,只是將 Label 的 Text 屬性的資料繫結改為呼叫一個自訂方法 (必須為 public 或 protected 方法)

Text='<%# YesOrNo(Eval("欄位名稱")) %>'

並撰寫後端程式碼如下:
protected string YesOrNo(object o)
{
  string s = o == DbNull.Value ? "" : Convert.ToString(o);
  return s == "Y" ? "是" : (s == "N" ? "否" : "");
}
這樣的好處是

  1. 不用數格子
  2. 沒有複雜的資料繫結語法
  3. 無論從何種資料來源做資料繫結,都可以適用
  4. 可檢查資料是否為 DbNull
提供給大家做參考

2 則留言:

Eden 提到...

讚的啦!
最近剛好有用到這方面的資料!
謝謝分享!

SHAO-WEI 提到...

感謝分享~
我用的是第一種方法...
終於解決了我的問題,感謝~