Datagrid 控制項是 Microsoft? ASP.NET 中功能最強、用途最廣的 Web 控制項之一,這一點已經得到了 ASP.NET 權威人士的認同。雖然 Datagrid 控制項便於使用,但同樣易於給使用者帶來麻煩。以下是許多人所犯的一些錯誤,這些人包括從初學者到富有經驗的 .NET 專家。您可以看到許多苦悶的使用者在 ASP.NET 新聞群組和論壇就這些錯誤提出問題。遵循本文概述的相當簡單的步驟,可以協助您避免這些錯誤,並節約大量的開發時間。
可以使用Datagrid 建立列表資料而沒有使用
我知道您不會再使用如下所示的代碼,但 ASP.NET 領域中許多守舊的使用者仍在繼續使用它們:
Response.Write("<table>")
While MyDataReader.Read()
Response.Write("<tr>")
Response.Write("<td>")
Response.Write(MyDataReader(0))
Response.Write("</td>")
Response.Write("</tr>")
Loop
Response.Write("</table>") |
可以對以上虢屑蚧蠱浣鑫?BR>
| <asp:datagrid runat="server" datasource="MyDataReader"/> |
並調用 .DataBind() 方法。即使需要對HTML輸出進行特殊的控制,您也可以在使用者介面上記錄集的內容重複出現的情況下,使用某個資料 Web 控制項。
忘記在 Page_Load 事件中檢查 IsPostBack
最常見的錯誤之一是忘記在資料繫結之前檢查頁面的 IsPostBack 條件。例如,Datagrid 處於“Edit”(編輯)模式時,忽略該項檢查將導致已編輯的值被資料來源中的原始值覆蓋。然而,該規則至少有一個主要的例外,請參閱持續使用大型 ViewState。
以下是包含 IsPostBack 檢查的一個典型 Page_Load 事件。BindGrid() 是一個常式,用於匯入並設定 Datagrid 的資料來源,並調用 DataBind() 方法。
Sub Page_Load
If Not IsPostBack Then
BindGrid()
End If
End Sub |
需要更大的靈活性時,仍堅持使用自動產生的列
如果 Datagrid 所處的環境需要任何一種特殊格式,或是需要使用 Datagrid 中的其他任何 Web 控制項,那麼必須關閉 AutoGenerateColumns。將 AutoGenerateColumns 屬性的設定保持為“True”(預設設定)的做法,僅在最簡單的 Datagrid 方案中有效。但對幾乎所有實際的應用程式,必須將該屬性設定為“False”,並在 Datagrid 聲明的 <columns></columns> 段中明確地指定列。Microsoft Visual Studio? .NET 使用者可以使用屬性產生器以圖形化的方式建立這些列。
注意:如果將 AutoGenerateColumns 的設定保持為“True”,並且在 Datagrid 的 <columns> 段中指定了列,那麼最終將得到對列的重複設定。系統將首先顯示特別聲明的列,隨後是所有自動產生的列。
嘗試僅使用控制項 ID 來引用 Datagrid 項目中的控制項
許多人沒有認識到,對於 Datagrid 的 TemplateColumn 下的 ItemTemplate 中的控制項(例如帶有“MyTextBox”ID 的 TextBox 控制項),不能在後面的代碼或是在 ASPX 頁面的 <script> 段中用如下所示的代碼來直接調用該控制項:
| Dim MyValue As String = MyTextBox.Text |
該代碼將導致可怕的“名稱‘MyTextBox’沒有聲明”錯誤。
因為 Datagrid 是由多個行(項目)組成的,所以資料來源中的每一行實際都會有一個單獨的“MyTextBox”執行個體。ASP.NET 在每個控制項的 ID 前面加上該控制項階層中每個命名容器的 ID,這樣 Textbox 將具有唯一的 ID,與頁面中所有其他控制項的 ID 都不相同。例如,如果 MyTextBox 處於 DataGrid1 中,那麼產生的 ID 將是 DataGrid1:_ctl2:MyTextBox。“_ctl2”代表 MyTextBox 所處的當前行。頁面中其他 MyTextBox 執行個體的 ID 可能是 DataGrid1:_ctl3:MyTextBox、DataGrid1:_ctl4:MyTextBox 等等。要檢索需要尋找的“MyTextBox”值,需要對適當的 DataGridItem 調用 FindControl 方法。該 DataGridItem 用作 TextBox 的父命名容器。
HTML:
<asp:Datagrid runat="server" id="Datagrid1">
<Columns>
<asp:TemplateColumn>
<ItemTemplate>
<asp:TextBox runat="server" id="MyTextBox"/>
</ItemTemplate>
</asp:TemplateColumn>
</Columns> |
代碼:
Sub DataGrid1_UpdateCommand(sender As Object, e As DataGridCommandEventArgs)
Dim MyValue As String = CType(e.Item.FindControl("MyTextBox"), TextBox).Text
'對 MyValue 執行操作
End Sub |
對 FindControl 調用的結果調用 CType,將會把傳回值由 Object 類型強制轉換成 TextBox 類型,以訪問 .Text 屬性。
忘記在每個 Datagrid 事件中執行 .DataBind() 調用,從而導致回傳
一個常見的問題是:“當我點擊 Datagrid 某一行中的 Edit(編輯)連結時,頁面回傳,且不包含任何資料。這是什麼錯誤?”問題在於資料僅在頁面第一次被調用時綁定到網格。在每個 Datagrid 事件(Edit、Update、Cancel、Page 或 Sort)中,請確保設定了 Datagrid 的 Datasource 屬性(除非已經在 <asp:Datagrid> 聲明中通過聲明的方式進行了設定),並對 Datagrid 調用了 DataBind() 方法。
運行時不必要地在 Datagrid 中動態建立 Datagrid 控制項或列
在某些業務和技術方案中,在運行時建立 ASP.NET 控制項是必要的,也是完全合適的。例如,有時需要在選擇其他頁面選項後,才能在運行時確定使用者介面。或是要建立一個複合伺服器控制項,其中的每個子控制項都需要動態建立,因為無法以聲明的方式建立這些子控制項。如果遇到這些情況,請注意,提交頁面時不要保留這些動態控制項。必須在頁面生命週期的早期,在每次回傳時重新建立動態控制項(例如在 Page_Init 事件中)。警言:建立控制項要早,建立控制項要勤。有關如何動態建立控制項的詳細資料,請參閱 Microsoft Knowledge Base 文章 HOW TO:Dynamically Create Controls in ASP.NET with Visual Basic .NET。
然而,如果 Datagrid 應用程式中不是一定需要動態建立控制項,請避免使用該技術,以免遇到麻煩。儘管可能建立動態 Datagrid,但它們會引發各種事件,這通常都會令人頭疼。換句話說,不要動態建立控制項,以避免因為建立控制項使 ASPX 檔案變得散亂。
持續使用大型 ViewState
Datagrid 控制項會在頁面中添加大量的 ViewState,這一點令人討厭,因為這會導致呈現給使用者的頁面的總體大小急劇增加。要使頁面大小不增加,最簡單的方法是無論對整個頁面,還是單獨對某些特定的控制項,都禁用 ViewState。例如,如果頁面不產生回傳,那麼對整個頁面禁用 ViewState 是安全的。否則,請對兩次回傳之間狀態資訊不會發生更改的各個控制項禁用 ViewState,或者對不需要隱藏欄位來跟蹤自身狀態的那些控制項禁用 ViewState。
對 Datagrid 控制項或包含 Datagrid 的頁面禁用 ViewState 時,如果 Datagrid 會啟動回傳事件,那麼需要執行一些特殊的步驟。首先,必須在每次回傳時在 Page_Load 中重新綁定 Datagrid。這有違常規做法(以及上述第二個問題中的描述)。但如果禁用 ViewState,該步驟是必需的,這樣在執行 Page_Load 後可以正確地引發其他 Datagrid 事件。如果要處理以下 Datagrid 事件中的任何一部分(或全部),那麼還需要在 ViewState 中手動儲存一些 Datagrid 屬性。例如,在禁用了 ViewState 的 Datagrid 中進行編輯時,只要是在 Page_Load 中第一次綁定 Datagrid 之前重新儲存 EditItemIndex,且 Datagrid 處於編輯模式,那麼只需將 EditItemIndex 儲存到 ViewState 就夠了。
表 1:Datagrid 事件與 ViewState 的依賴關係
| 事件 |
是否依賴於 ViewState? |
要儲存在 ViewState 中的欄位 |
| ItemCreated |
|
無 |
| ItemDataBound |
|
無 |
| SortCommand |
是 |
SortExpression |
| EditCommand |
是 |
EditItemIndex |
| PageIndexChanged |
是 |
CurrentPageIndex |
| SelectedIndexChanged |
|
無 |
清單 1:啟用編輯、排序和分頁,但禁用 ViewState 的 Datagrid 的範例程式碼。
Sub Page_Load
If Not ViewState("EditItemIndex") Is Nothing Then
Datagrid1.EditItemIndex = ViewState("EditItemIndex")
End If
If Not ViewState("CurrentPageIndex") Is Nothing Then
Datagrid1.CurrentPageIndex = ViewState("CurrentPageIndex")
End If
BindGrid()
End Sub
Sub BindGrid()
Dim DV As DataView
DV = GetDataSource()
DV.Sort = ViewState("SortExpression")
Datagrid1.DataSource = DV
Datagrid1.DataBind()
End Sub
Sub Datagrid1_SortCommand(s As Object, e As DataGridSortCommandEventArgs)
ViewState("SortExpression") = e.SortExpression
BindGrid()
End Sub
Sub Datagrid1_EditCommand(s As Object, e As DatagridCommandEventArgs)
Datagrid1.EditItemIndex = e.Item.ItemIndex
ViewState("EditItemIndex") = e.Item.ItemIndex
BindGrid()
End Sub
Sub Datagrid1_PageIndexChanged(s as Object, e As DataGridPageChangedEventArgs)
Datagrid1.CurrentPageIndex = e.NewPageIndex
ViewState("CurrentPageIndex") = e.NewPageIndex
BindGrid()
End Sub |
使用 ItemDataBound 或 ItemCreated 事件時,忘記檢查適當的 ListItemType
Datagrid 控制項對每個資料行引發兩個事件。首次將每行添加到 Datagrid 時將引發 ItemCreated 事件,將資料繫結到每行時將引發 ItemDataBound 事件。添加儲存格到 Datagrid 的表格輸出時,這些事件可以用於控制每個儲存格的外觀或內容。例如,可以基於數值的範圍修改儲存格的背景顏色。但關鍵是要記住,這些事件的引髮針對的是所有 Datagrid 項目類型,包括頁首、頁尾和分頁程式項目。如果執行 ItemDataBound 事件期間,沒有在引用項目的資料之前仔細檢查項目類型,第一個項目(通常是標題列)就將發生錯誤。如果 Datagrid 啟用了分頁,且將其設定為在頂端顯示,那麼第一個項目就會成為分頁程式項目。以下範例程式碼顯示如何在引用項目資料之前進行正確的 ListItemType 檢查。不要忘了 AlternatingItem!
Sub DataGrid1_ItemDataBound(source As Object,e As DataGridItemEventArgs)
If (e.Item.ItemType = ListItemType.Item Or e.Item.ItemType = ListItemType.AlternatingItem) Then
If e.Item.DataItem("ForumDate") < DateTime.Today Then
e.Item.Cells(1).BackColor =System.Drawing.Color.FromName("#ffccff")
End If
End If
End Sub |
需要對產生的 HTML 有更多的控制時,過多地使用了 Datagrid(Repeater 也許是更好的選擇)
如果懶散的程式員喜歡 Datagrid 控制項(因為 Datagrid 控制項為他們完成了很多工作),那麼有著極強控制欲的程式員必定喜歡 重複器控制項。如果需要或希望完全控制建立的所有 HTML,請使用 重複器控制項,它能協助您完成該任務。重複器控制項在效能上也略佔優勢,因為它不像 Datagrid 控制項的所有內建功能那樣佔用系統資源。也可以考慮使用折衷的 DataList 控制項,它具備編輯和排序功能,同時還具有在一行內重複顯示記錄的功能。