前二篇文章介紹了自訂 GridView 使用的下拉清單欄位 (TBDropDownField),對如何繼承 BoundField 類別下來改寫自訂欄位應該有進一步的了解。在 GridView 中輸入日期也常蠻常見的需求,在本文將再實作一個 GridView 使用的日期欄位,在欄位儲存格使用 TBDateEdit 控制項來編輯資料。
程式碼下載:ASP.NET Server Control - Day25.rar
Northwnd 資料庫下載:NORTHWND.rar
一、繼承 TBBaseBoundField 實作 TDateField
GridView 的日期欄位需要繫結資料,一般的作法是由 BoundField 繼承下來改寫;不過我們之前已經有繼承 BoundField 製作一個 TBBaseBoundField 的自訂欄位基底類別 (詳見「 [ASP.NET 控制項實作 Day23] 自訂 GridVie 欄位類別 - 實作 TBDropDownField 欄位類別」 一文),所以我們要實作的日期欄位直接繼承 TBBaseBoundField 命名為 TDateField,並覆寫 CreateField 方法,傳回 TDateField 物件。
- '''
- ''' 日期欄位。
- '''
- Public Class TBDateField
- Inherits TBBaseBoundField
- Protected Overrides Function CreateField() As DataControlField
- Return New TBDateField()
- End Function
- End Class
自訂欄位類別主要是要覆寫 InitializeDataCell 方法做資料儲存格初始化、覆寫 OnDataBindField 方法將欄位值繫結至 BoundField 物件、覆寫 ExtractValuesFromCell 方法來擷取儲存格的欄位值,下面我們將針對這幾個需要覆寫的方法做一說明。
二、覆寫 InitializeDataCell 方法 - 資料儲存格初始化
首先覆寫 InitializeDataCell 方法處理資料儲存格初始化,當唯讀狀態時使用 Cell 來呈現資料;若為編輯狀態時,則在 Cell 中加入 TBDateEdit 控制項,並將 TBDateField 的屬性設定給 TBDateEdit 控制項的相關屬性。然後將儲存格 (DataControlFieldCell) 或日期控制項 (TDateEdit) 的 DataBinding 事件導向 OnDataBindField 事件處理方法。
- '''
- ''' 資料儲存格初始化。
- '''
- ''' 要初始化的儲存格。
- ''' 資料列狀態。
- Protected Overrides Sub InitializeDataCell(ByVal Cell As DataControlFieldCell, ByVal RowState As DataControlRowState)
- Dim oDateEdit As TBDateEdit
- Dim oControl As Control
- If Me.CellIsEdit(RowState) Then
- '編輯狀態在儲存格加入 TBDateEdit 控制項
- oDateEdit = New TBDateEdit()
- oDateEdit.FirstDayOfWeek = Me.FirstDayOfWeek
- oDateEdit.ShowWeekNumbers = Me.ShowWeekNumbers
- oDateEdit.CalendarStyle = Me.CalendarStyle
- oDateEdit.Lang = Me.Lang
- oDateEdit.ShowTime = Me.ShowTime
- oControl = oDateEdit
- Cell.Controls.Add(oControl)
- Else
- oControl = Cell
- End If
- If (oControl IsNot Nothing) AndAlso MyBase.Visible Then
- AddHandler oControl.DataBinding, New EventHandler(AddressOf Me.OnDataBindField)
- End If
- End Sub
TDateEdit 控制項為筆者自行撰寫的日期控制項,TDateEdit 控制項的相關細節可以參考筆者部落格下面幾篇文章有進一步說明。
日期控制項實作教學(1) - 結合 JavaScript
日期控制項實作教學(2) - PostBack 與 事件
TBDateEdit 日期控制項 - 1.0.0.0 版 (Open Source)
![]()
三、覆寫 OnDataBindField 方法 - 將欄位值繫結至 BoundField 物件
當 GridView 執行 DataBind 時,每個儲存格的 DataBinding 事件都會被導向 OnDataBindField 方法,此方法中我們會由資料來源取得指定欄位值,處理此欄位值的格式化時,將欄位值呈現在 Cell 或 TDateEdit 控制項上。
- '''
- ''' 將欄位值繫結至 BoundField 物件。
- '''
- ''' 控制項。
- ''' 事件引數。
- Protected Overrides Sub OnDataBindField(ByVal sender As Object, ByVal e As EventArgs)
- Dim oControl As Control
- Dim oDateEdit As TBDateEdit
- Dim oNamingContainer As Control
- Dim oDataValue As Object '欄位值
- Dim bEncode As Boolean '是否編碼
- Dim sText As String '格式化字串
- oControl = DirectCast(sender, Control)
- oNamingContainer = oControl.NamingContainer
- oDataValue = Me.GetValue(oNamingContainer)
- bEncode = ((Me.SupportsHtmlEncode AndAlso Me.HtmlEncode) AndAlso TypeOf oControl Is TableCell)
- sText = Me.FormatDataValue(oDataValue, bEncode)
- If TypeOf oControl Is TableCell Then
- If (sText.Length = 0) Then
- sText = " "
- End If
- DirectCast(oControl, TableCell).Text = sText
- Else
- If Not TypeOf oControl Is TBDateEdit Then
- Throw New HttpException(String.Format("{0}: Wrong Control Type", Me.DataField))
- End If
- oDateEdit = DirectCast(oControl, TBDateEdit)
- If Me.ApplyFormatInEditMode Then
- oDateEdit.Text = sText
- ElseIf (Not oDataValue Is Nothing) Then
- oDateEdit.Text = oDataValue.ToString
- End If
- End If
- End Sub
四、覆寫 ExtractValuesFromCell 方法 - 擷取儲存格的欄位值
當用戶端使用 GridView 編輯後執行更新動作時,會呼叫 ExtractValuesFromCell 方法,來取得儲存格的欄位值,以便寫入資料來源。所以我們要覆寫 ExtractValuesFromCell 方法,將 Cell 或 TDateEdit 控制項的值取出填入具 IOrderedDictionary 介面的物件。
- '''
- ''' 使用指定 DataControlFieldCell 的值填入指定的 IDictionary 物件。
- '''
- ''' 用於儲存指定儲存格的值。
- ''' 包含要擷取值的儲存格。
- ''' 資料列的狀態。
- ''' true 表示包含唯讀欄位的值,否則為 false。
- Public Overrides Sub ExtractValuesFromCell( _
- ByVal Dictionary As IOrderedDictionary, _
- ByVal Cell As DataControlFieldCell, _
- ByVal RowState As DataControlRowState, _
- ByVal IncludeReadOnly As Boolean)
- Dim oControl As Control = Nothing
- Dim sDataField As String = Me.DataField
- Dim oValue As Object = Nothing
- Dim sNullDisplayText As String = Me.NullDisplayText
- Dim oDateEdit As TBDateEdit
- If (((RowState And DataControlRowState.Insert) = DataControlRowState.Normal) OrElse Me.InsertVisible) Then
- If (Cell.Controls.Count > 0) Then
- oControl = Cell.Controls.Item(0)
- oDateEdit = TryCast(oControl, TBDateEdit)
- If (Not oDateEdit Is Nothing) Then
- oValue = oDateEdit.Text
- End If
- ElseIf IncludeReadOnly Then
- Dim s As String = Cell.Text
- If (s = " ") Then
- oValue = String.Empty
- ElseIf (Me.SupportsHtmlEncode AndAlso Me.HtmlEncode) Then
- oValue = HttpUtility.HtmlDecode(s)
- Else
- oValue = s
- End If
- End If
- If (Not oValue Is Nothing) Then
- If TypeOf oValue Is String Then
- If (CStr(oValue).Length = 0) AndAlso Me.ConvertEmptyStringToNull Then
- oValue = Nothing
- ElseIf (CStr(oValue) = sNullDisplayText) AndAlso (sNullDisplayText.Length > 0) Then
- oValue = Nothing
- End If
- End If
- If Dictionary.Contains(sDataField) Then
- Dictionary.Item(sDataField) = oValue
- Else
- Dictionary.Add(sDataField, oValue)
- End If
- End If
- End If
- End Sub
五、測試程式
我們使用 Northwnd 資料庫的 Employees 資料表為例,在 GridView 加入自訂的 TBDateField 欄位繫結 BirthDate 欄位,另外加入另一個 BoundField 的唯讀欄位,也同樣繫結 BirthDate 欄位來做比較。
- < bee:TBDateField DataField="BirthDate" HeaderText="BirthDate"
- SortExpression="BirthDate" DataFormatString="{0:d}"
- ApplyFormatInEditMode="True" CalendarStyle="Winter" />
- < asp:BoundField DataField="BirthDate" HeaderText="BirthDate"
- SortExpression="BirthDate" DataFormatString="{0:d}"
- ApplyFormatInEditMode="True" ReadOnly="true" />
執行程式,在編輯資料列時,TBDateField 就會以 TDateEdit 控制項來進行編輯。
使用 TDateEdit 編輯欄位值後,按「更新」鈕,資料就會被寫回資料庫。
備註:本文同步發佈於「第一屆iT邦幫忙鐵人賽」,如果你覺得這篇文章對您有幫助,記得連上去推鑒此文增加人氣 ^^
http://ithelp.ithome.com.tw/question/10013083
http://ithelp.ithome.com.tw/question/10013091
