常見Datagrid錯誤

來源:互聯網
上載者:User
datagrid|錯誤


摘要:學習如何避免在使用 ASP.NET Datagrid 控制項進行開發時可能發生的一些常見錯誤(本文包含一些指向英文網站的連結)。

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>")
可以對以上代碼進行簡化,使其僅為:

<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 中實現分頁的資訊,請參閱 Paging in DataGrid QuickStart Tutorial。在 Scott Mitchell 的文章 Creating a Pageable, Sortable DataGrid 中可以找到更多的資訊。

忘記在每個 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 控制項,它具備編輯和排序功能,同時還具有在一行內重複顯示記錄的功能。

參考資料
DotNetJohn 網站上的 Viewstate
Datagrid QuickStart Tutorials
有關 DataGrid Web 伺服器控制項的重要問題
Creating a Pageable, Sortable DataGrid




相關文章

E-Commerce Solutions

Leverage the same tools powering the Alibaba Ecosystem

Learn more >

Apsara Conference 2019

The Rise of Data Intelligence, September 25th - 27th, Hangzhou, China

Learn more >

Alibaba Cloud Free Trial

Learn and experience the power of Alibaba Cloud with a free trial worth $300-1200 USD

Learn more >

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。