前二篇文章介紹了自訂 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 TBDateFieldInherits TBBaseBoundFieldProtected Overrides Function CreateField() As DataControlFieldReturn New TBDateField()End FunctionEnd 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 TBDateEditDim oControl As ControlIf Me.CellIsEdit(RowState) Then'編輯狀態在儲存格加入 TBDateEdit 控制項oDateEdit = New TBDateEdit()oDateEdit.FirstDayOfWeek = Me.FirstDayOfWeekoDateEdit.ShowWeekNumbers = Me.ShowWeekNumbersoDateEdit.CalendarStyle = Me.CalendarStyleoDateEdit.Lang = Me.LangoDateEdit.ShowTime = Me.ShowTimeoControl = oDateEditCell.Controls.Add(oControl)ElseoControl = CellEnd IfIf (oControl IsNot Nothing) AndAlso MyBase.Visible ThenAddHandler oControl.DataBinding, New EventHandler(AddressOf Me.OnDataBindField)End IfEnd 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 ControlDim oDateEdit As TBDateEditDim oNamingContainer As ControlDim oDataValue As Object '欄位值Dim bEncode As Boolean '是否編碼Dim sText As String '格式化字串oControl = DirectCast(sender, Control)oNamingContainer = oControl.NamingContaineroDataValue = Me.GetValue(oNamingContainer)bEncode = ((Me.SupportsHtmlEncode AndAlso Me.HtmlEncode) AndAlso TypeOf oControl Is TableCell)sText = Me.FormatDataValue(oDataValue, bEncode)If TypeOf oControl Is TableCell ThenIf (sText.Length = 0) ThensText = " "End IfDirectCast(oControl, TableCell).Text = sTextElseIf Not TypeOf oControl Is TBDateEdit ThenThrow New HttpException(String.Format("{0}: Wrong Control Type", Me.DataField))End IfoDateEdit = DirectCast(oControl, TBDateEdit)If Me.ApplyFormatInEditMode ThenoDateEdit.Text = sTextElseIf (Not oDataValue Is Nothing) ThenoDateEdit.Text = oDataValue.ToStringEnd IfEnd IfEnd 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 = NothingDim sDataField As String = Me.DataFieldDim oValue As Object = NothingDim sNullDisplayText As String = Me.NullDisplayTextDim oDateEdit As TBDateEditIf (((RowState And DataControlRowState.Insert) = DataControlRowState.Normal) OrElse Me.InsertVisible) ThenIf (Cell.Controls.Count > 0) ThenoControl = Cell.Controls.Item(0)oDateEdit = TryCast(oControl, TBDateEdit)If (Not oDateEdit Is Nothing) ThenoValue = oDateEdit.TextEnd IfElseIf IncludeReadOnly ThenDim s As String = Cell.TextIf (s = " ") ThenoValue = String.EmptyElseIf (Me.SupportsHtmlEncode AndAlso Me.HtmlEncode) ThenoValue = HttpUtility.HtmlDecode(s)ElseoValue = sEnd IfEnd IfIf (Not oValue Is Nothing) ThenIf TypeOf oValue Is String ThenIf (CStr(oValue).Length = 0) AndAlso Me.ConvertEmptyStringToNull ThenoValue = NothingElseIf (CStr(oValue) = sNullDisplayText) AndAlso (sNullDisplayText.Length > 0) ThenoValue = NothingEnd IfEnd IfIf Dictionary.Contains(sDataField) ThenDictionary.Item(sDataField) = oValueElseDictionary.Add(sDataField, oValue)End IfEnd IfEnd IfEnd 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