如果您的小組與許多組織一樣,已經將商務邏輯和/或資料訪問邏輯分成單獨的組件或組件集,而剩下的 ASP.NET 檔案、ASPX 及其代碼只包含純粹的表示邏輯。(“純粹”是一個相對的詞語。)但是,即使是展示層的邏輯有時也會重複使用,這樣,下次某個使用者來到您門前說,“我想讓我的應用程式在‘財務’方面看起來與蘇茜的一樣”時,您可以重複使用“財務”應用程式的部分表示內容快速為其構建一個這樣的應用程式。您可能還想將一些邏輯打包,在 Web 上銷售或在您的 Web 網站分發。ASP.NET 使這一切比以往更容易實現,因為它使您可以建立自己的伺服器控制項,或從現有的類型匯出列類型,從而獲得所需的功能。
DropDownList 方案
假設您正在本地 Microsoft SQL Server? 中編輯 Northwind 資料庫(或做其他工作),您想使您的使用者(我們稱之為 Ed,倉庫保管員)可以編輯 Orders 表。其中一個欄位包含運輸資訊 (ShipVia),Ed 要能夠修改該欄位的資訊。在顯示模式下,運輸公司應顯示為純文字。當 Ed 單擊 Edit(編輯)按鈕時,您不光要為他提供一個 TextBox 以編輯運輸方式代碼(1、2 或 3),還要為他提供一個包含可以選擇不同運輸公司的 DropDownList。(因為 Ed 記不住哪個運輸公司對應哪個號碼,所以,DropDownList 方案可以協助他解決這個問題。)
內建的 Datagrid 列
瞭解問題的大概情況後,現在我們後退一步,看一下 ASP.NET 中構建的 5 種 Datagrid 列類型及其父類型 DataGridColumn。
Sub BindGrid()
Dim SQL As String = "SELECT OrderID,
ShipName, ShipCountry, ShipVia FROM Orders"
Dim DA As SqlDataAdapter = New SqlDataAdapter(SQL, ConnStr)
Dim DS As New DataSet
DA.Fill(DS, "Orders")
DataGrid1.DataSource = DS.Tables("Orders").DefaultView
DataGrid1.DataBind()
End Sub
當前編輯的項目是在觸發 Datagrid 的 ItemDataBound 事件時綁定到 DropDownList 的。使用 ItemDataBound 事件時,請檢查當前項目的 ListItemType,否則您可能會發現您正在使用 HeaderItem 或其他不適用的項目類型。為 EditItem 引用 DropDownList 控制項。在下面的代碼中,我直接使用儲存格控制項集進行說明(為了與後面的樣本保持一致),但是,您可以採用簡單的方法,直接為 DropDownList 控制項指定 ID,並使用 Datagrid 項目的 FindControl 方法定位控制項引用。由於 Datagrid 被綁定到 DataTable 的預設視圖,而該視圖的元素屬於 DataRowView 類型,所以您可以將當前項目的 DataItem 屬性轉換為一個 DataRowView 執行個體。這樣,您可以按欄位名直接引用 DataItem 中的欄位。使用這種方法,將“ShipVia”的當前值儲存到該記錄中,並使用它選擇相應的下拉式清單項。
Private Sub DataGrid1_ItemDataBound(ByVal sender As Object, _
ByVal e As System.Web.UI.WebControls.DataGridItemEventArgs) _
Handles DataGrid1.ItemDataBound
If e.Item.ItemType = ListItemType.EditItem Then
Dim DRV As DataRowView = CType(e.Item.DataItem, DataRowView)
Dim CurrentShip As String = DRV("ShipVia")
Dim DDL As DropDownList = CType(e.Item.Cells(4).Controls(1), DropDownList)
Dim SQL As String = "SELECT ShipperID, CompanyName FROM Shippers ORDER BY ShipperID"
Dim DA As SqlDataAdapter = New SqlDataAdapter(SQL, ConnStr)
Dim DS As New DataSet
Dim item As ListItem
DA.Fill(DS, "Shippers")
DDL.DataSource = DS.Tables("Shippers").DefaultView
DDL.DataTextField = "CompanyName"
DDL.DataValueField = "ShipperID"
DDL.DataBind()
item = DDL.Items.FindByValue(CurrentShip)
If Not item Is Nothing Then item.Selected = True
End If
End Sub
最後,編寫從 DropDownList 中檢索當前選定值的代碼,並執行資料庫更新:
Private Sub DataGrid1_UpdateCommand(ByVal source As Object, _
ByVal e As System.Web.UI.WebControls.DataGridCommandEventArgs) _
Handles DataGrid1.UpdateCommand
Dim DDL As DropDownList = CType(e.Item.Cells(4).Controls(1), DropDownList)
Dim NewShip As Integer = DDL.SelectedValue
Dim OrderID As Integer = Int32.Parse(e.Item.Cells(1).Text)
Dim SQL As String = "UPDATE Orders SET ShipVia=@Ship WHERE OrderID=@ID"
Dim Conn As SqlConnection = New SqlConnection(ConnStr)
Dim Cmd As New SqlCommand(SQL, Conn)
Cmd.Parameters.Add(New SqlParameter("@Ship", NewShip))
Cmd.Parameters.Add(New SqlParameter("@ID", OrderID))
Conn.Open()
Cmd.ExecuteNonQuery()
Conn.Close()
DataGrid1.EditItemIndex = -1
BindGrid()
End Sub
Public Overrides Sub InitializeCell(ByVal cell As TableCell, _
ByVal columnIndex As Integer, _
ByVal itemType As ListItemType)
MyBase.InitializeCell(cell, columnIndex, itemType)
Select Case itemType
Case ListItemType.Header
cell.Text = HeaderText
Case ListItemType.Item, ListItemType.AlternatingItem
AddHandler cell.DataBinding, AddressOf ItemDataBinding
Case ListItemType.EditItem
AddHandler cell.DataBinding, AddressOf EditItemDataBinding
Dim DDL As New DropDownList
cell.Controls.Add(DDL)
End Select
End Sub
接下來是 ItemDataBinding 常式,當對 Datagrid 中的 Item 或 AlternatingItem 進行資料時,將觸發該常式。您需要引用回正在綁定的 TableCell,可以直接轉換傳遞給事件的“寄件者”對象,再使用 TableCell 的 NamingContainer 屬性引用當前的 DataGridItem。這裡只能以純文字格式顯示 DataField 的內容,就象顯示在 BoundColumn 中一樣。最後,如果使用者指定的欄位不存在,我將為使用者顯示更友好的錯誤資訊,而不是僅僅顯示“索引超出範圍”這樣的一般資訊。
Private Sub ItemDataBinding(ByVal sender As Object, ByVal e As EventArgs)
Dim cell As TableCell = CType(sender, TableCell)
Dim DGI As DataGridItem = CType(cell.NamingContainer, DataGridItem)
Try
cell.Text = DGI.DataItem(DataField)
Catch RangeEx As IndexOutOfRangeException
Throw New Exception("Specified DataField was not found.")
Catch OtherEx As Exception
Throw New Exception(OtherEx.InnerException.ToString)
End Try
End Sub
下一步,編寫 EditItemDataBinding 事件的代碼,當某個行進入“編輯”模式時,將在我們的自訂欄儲存格上觸發該事件。再次引用目前的儲存格並在調用 InitializeCell 方法時插入 DropDownList 控制項。在 DropDownList 中添加一個空項目作為第一個選項,如果列中的當前資料與您從 DataSource 集合中選擇並放在列表中的任何項目都不匹配,則選擇該選項。
Private Sub EditItemDataBinding(ByVal sender As Object, _
ByVal e As EventArgs)
Dim cell As TableCell = CType(sender, TableCell)
Dim DDL As DropDownList = _
CType(cell.Controls(0), DropDownList)
Dim DataSourceItem As Object
Dim item As ListItem
Dim DGI As DataGridItem
'首先添加一個空選項
DDL.Items.Add(New ListItem(""))
For Each DataSourceItem In DataSource
Select Case DataSourceItem.GetType.ToString
Case "System.String" '應用到 ArrayList 樣本
item = New ListItem(DataSourceItem, DataSourceItem)
DDL.Items.Add(item)
Case "System.Data.DataRowView"
Dim DRV As DataRowView = _
CType(DataSourceItem, DataRowView)
item = New_
ListItem(DRV(DataTextField), DRV(DataValueField))
DDL.Items.Add(item)
Case Else
Throw New Exception("Invalid DataSource type.")
End Select
Next
Try
DGI = CType(cell.NamingContainer, DataGridItem)
item = DDL.Items.FindByValue(DGI.DataItem(DataField))
Catch RangeEx As IndexOutOfRangeException
Throw New Exception("Specified DataField was not found.")
Catch OtherEx As Exception
Throw New Exception(OtherEx.InnerException.ToString)
End Try
If Not item Is Nothing Then item.Selected = True
End Sub
Dim DDC As MyCustomColumn.DropDownColumn
DDC = CType(DataGrid1.Columns(4), MyCustomColumn.DropDownColumn)
Dim AL As New ArrayList
AL.Add("Shipping Company A")
AL.Add("Shipping Company B")
AL.Add("Shipping Company C")
DDC.DataSource = AL
下面是運行此代碼的結果:
Private Sub DataGrid1_UpdateCommand( ByVal source As Object, _
ByVal e As System.Web.UI.WebControls.DataGridCommandEventArgs) _
Handles DataGrid1.UpdateCommand
Dim CustomDDL As DropDownList = _
CType(e.Item.Cells(4).Controls(0), DropDownList)
Dim NewShip As Integer = CustomDDL.SelectedValue
Dim OrderID As Integer = Int32.Parse(e.Item.Cells(1).Text)
Dim SQL As String = "UPDATE Orders SET ShipVia=@Ship WHERE OrderID=@ID"
Dim Conn As SqlConnection = New SqlConnection(ConnStr)
Dim Cmd As New SqlCommand(SQL, Conn)
Cmd.Parameters.Add(New SqlParameter("@Ship", NewShip))
Cmd.Parameters.Add(New SqlParameter("@ID", OrderID))
Conn.Open()
Cmd.ExecuteNonQuery()
Conn.Close()
DataGrid1.EditItemIndex = -1
BindGrid()
End Sub
小結