前二篇文章介紹了自訂 GridView 使用的下拉清單欄位 (TBDropDownField),對如何繼承 BoundField 類別下來改寫自訂欄位應該有進一步的了解。在 GridView 中輸入日期也常蠻常見的需求,在本文將再實作一個 GridView 使用的日期欄位,在欄位儲存格使用 TBDateEdit 控制項來編輯資料。
前二篇文章介紹了自訂 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 物件。
''' <summary>
''' 日期欄位。
''' </summary>
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 事件處理方法。
''' <summary>
''' 資料儲存格初始化。
''' </summary>
''' <param name="Cell">要初始化的儲存格。</param>
''' <param name="RowState">資料列狀態。</param>
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 控制項上。
''' <summary>
''' 將欄位值繫結至 BoundField 物件。
''' </summary>
''' <param name="sender">控制項。</param>
''' <param name="e">事件引數。</param>
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 介面的物件。
''' <summary>
''' 使用指定 DataControlFieldCell 的值填入指定的 IDictionary 物件。
''' </summary>
''' <param name="Dictionary">用於儲存指定儲存格的值。</param>
''' <param name="Cell">包含要擷取值的儲存格。</param>
''' <param name="RowState">資料列的狀態。</param>
''' <param name="IncludeReadOnly">true 表示包含唯讀欄位的值,否則為 false。</param>
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