前二篇文章介紹了自訂 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 物件。

 

  1. '''    
  2. ''' 日期欄位。   
  3. '''    
  4. Public Class TBDateField   
  5.     Inherits TBBaseBoundField   
  6.   
  7.     Protected Overrides Function CreateField() As DataControlField   
  8.         Return New TBDateField()   
  9.     End Function  
  10. End Class  

 

自訂欄位類別主要是要覆寫 InitializeDataCell 方法做資料儲存格初始化、覆寫 OnDataBindField 方法將欄位值繫結至 BoundField 物件、覆寫 ExtractValuesFromCell 方法來擷取儲存格的欄位值,下面我們將針對這幾個需要覆寫的方法做一說明。

image

 

二、覆寫 InitializeDataCell 方法 - 資料儲存格初始化

首先覆寫 InitializeDataCell 方法處理資料儲存格初始化,當唯讀狀態時使用  Cell 來呈現資料;若為編輯狀態時,則在 Cell 中加入 TBDateEdit 控制項,並將 TBDateField 的屬性設定給 TBDateEdit 控制項的相關屬性。然後將儲存格 (DataControlFieldCell) 或日期控制項 (TDateEdit) 的 DataBinding 事件導向 OnDataBindField 事件處理方法。

 

  1. '''    
  2. ''' 資料儲存格初始化。   
  3. '''    
  4. ''' 要初始化的儲存格。   
  5. ''' 資料列狀態。   
  6. Protected Overrides Sub InitializeDataCell(ByVal Cell As DataControlFieldCell, ByVal RowState As DataControlRowState)   
  7.     Dim oDateEdit As TBDateEdit   
  8.     Dim oControl As Control   
  9.   
  10.     If Me.CellIsEdit(RowState) Then  
  11.         '編輯狀態在儲存格加入 TBDateEdit 控制項   
  12.         oDateEdit = New TBDateEdit()   
  13.         oDateEdit.FirstDayOfWeek = Me.FirstDayOfWeek   
  14.         oDateEdit.ShowWeekNumbers = Me.ShowWeekNumbers   
  15.         oDateEdit.CalendarStyle = Me.CalendarStyle   
  16.         oDateEdit.Lang = Me.Lang   
  17.         oDateEdit.ShowTime = Me.ShowTime   
  18.         oControl = oDateEdit   
  19.         Cell.Controls.Add(oControl)   
  20.     Else  
  21.         oControl = Cell   
  22.     End If  
  23.   
  24.     If (oControl IsNot NothingAndAlso MyBase.Visible Then  
  25.         AddHandler oControl.DataBinding, New EventHandler(AddressOf Me.OnDataBindField)   
  26.     End If  
  27. End Sub  

TDateEdit 控制項為筆者自行撰寫的日期控制項,TDateEdit 控制項的相關細節可以參考筆者部落格下面幾篇文章有進一步說明。

日期控制項實作教學(1) - 結合 JavaScript
日期控制項實作教學(2) - PostBack 與 事件
TBDateEdit 日期控制項 - 1.0.0.0 版 (Open Source)

 

三、覆寫 OnDataBindField 方法 - 將欄位值繫結至 BoundField 物件

當 GridView 執行 DataBind 時,每個儲存格的 DataBinding 事件都會被導向 OnDataBindField 方法,此方法中我們會由資料來源取得指定欄位值,處理此欄位值的格式化時,將欄位值呈現在 Cell 或 TDateEdit 控制項上。

 

  1. '''    
  2. ''' 將欄位值繫結至 BoundField 物件。    
  3. '''    
  4. ''' 控制項。   
  5. ''' 事件引數。   
  6. Protected Overrides Sub OnDataBindField(ByVal sender As ObjectByVal e As EventArgs)   
  7.     Dim oControl As Control   
  8.     Dim oDateEdit As TBDateEdit   
  9.     Dim oNamingContainer As Control   
  10.     Dim oDataValue As Object            '欄位值   
  11.     Dim bEncode As Boolean              '是否編碼   
  12.     Dim sText As String                 '格式化字串   
  13.   
  14.     oControl = DirectCast(sender, Control)   
  15.     oNamingContainer = oControl.NamingContainer   
  16.     oDataValue = Me.GetValue(oNamingContainer)   
  17.     bEncode = ((Me.SupportsHtmlEncode AndAlso Me.HtmlEncode) AndAlso TypeOf oControl Is TableCell)   
  18.     sText = Me.FormatDataValue(oDataValue, bEncode)   
  19.   
  20.     If TypeOf oControl Is TableCell Then  
  21.         If (sText.Length = 0) Then  
  22.             sText = " "  
  23.         End If  
  24.         DirectCast(oControl, TableCell).Text = sText   
  25.     Else  
  26.         If Not TypeOf oControl Is TBDateEdit Then  
  27.             Throw New HttpException(String.Format("{0}: Wrong Control Type"Me.DataField))   
  28.         End If  
  29.   
  30.         oDateEdit = DirectCast(oControl, TBDateEdit)   
  31.         If Me.ApplyFormatInEditMode Then  
  32.             oDateEdit.Text = sText   
  33.         ElseIf (Not oDataValue Is NothingThen  
  34.             oDateEdit.Text = oDataValue.ToString   
  35.         End If  
  36.     End If  
  37. End Sub  

 

四、覆寫 ExtractValuesFromCell 方法 - 擷取儲存格的欄位值

當用戶端使用 GridView 編輯後執行更新動作時,會呼叫 ExtractValuesFromCell 方法,來取得儲存格的欄位值,以便寫入資料來源。所以我們要覆寫 ExtractValuesFromCell 方法,將 Cell 或 TDateEdit 控制項的值取出填入具 IOrderedDictionary 介面的物件。

  1. '''    
  2. ''' 使用指定 DataControlFieldCell 的值填入指定的 IDictionary 物件。    
  3. '''    
  4. ''' 用於儲存指定儲存格的值。   
  5. ''' 包含要擷取值的儲存格。   
  6. ''' 資料列的狀態。   
  7. ''' true 表示包含唯讀欄位的值,否則為 false。   
  8. Public Overrides Sub ExtractValuesFromCell( _   
  9.     ByVal Dictionary As IOrderedDictionary, _   
  10.     ByVal Cell As DataControlFieldCell, _   
  11.     ByVal RowState As DataControlRowState, _   
  12.     ByVal IncludeReadOnly As Boolean)   
  13.   
  14.     Dim oControl As Control = Nothing  
  15.     Dim sDataField As String = Me.DataField   
  16.     Dim oValue As Object = Nothing  
  17.     Dim sNullDisplayText As String = Me.NullDisplayText   
  18.     Dim oDateEdit As TBDateEdit   
  19.   
  20.     If (((RowState And DataControlRowState.Insert) = DataControlRowState.Normal) OrElse Me.InsertVisible) Then  
  21.         If (Cell.Controls.Count > 0) Then  
  22.             oControl = Cell.Controls.Item(0)   
  23.             oDateEdit = TryCast(oControl, TBDateEdit)   
  24.             If (Not oDateEdit Is NothingThen  
  25.                 oValue = oDateEdit.Text   
  26.             End If  
  27.         ElseIf IncludeReadOnly Then  
  28.             Dim s As String = Cell.Text   
  29.             If (s = " "Then  
  30.                 oValue = String.Empty   
  31.             ElseIf (Me.SupportsHtmlEncode AndAlso Me.HtmlEncode) Then  
  32.                 oValue = HttpUtility.HtmlDecode(s)   
  33.             Else  
  34.                 oValue = s   
  35.             End If  
  36.         End If  
  37.   
  38.         If (Not oValue Is NothingThen  
  39.             If TypeOf oValue Is String Then  
  40.                 If (CStr(oValue).Length = 0) AndAlso Me.ConvertEmptyStringToNull Then  
  41.                     oValue = Nothing  
  42.                 ElseIf (CStr(oValue) = sNullDisplayText) AndAlso (sNullDisplayText.Length > 0) Then  
  43.                     oValue = Nothing  
  44.                 End If  
  45.             End If  
  46.   
  47.             If Dictionary.Contains(sDataField) Then  
  48.                 Dictionary.Item(sDataField) = oValue   
  49.             Else  
  50.                 Dictionary.Add(sDataField, oValue)   
  51.             End If  
  52.         End If  
  53.     End If  
  54. End Sub  

 

五、測試程式

我們使用 Northwnd 資料庫的 Employees 資料表為例,在 GridView 加入自訂的 TBDateField 欄位繫結 BirthDate 欄位,另外加入另一個 BoundField 的唯讀欄位,也同樣繫結 BirthDate 欄位來做比較。

 

  1. < bee:TBDateField DataField="BirthDate" HeaderText="BirthDate"    
  2.     SortExpression="BirthDate" DataFormatString="{0:d}"    
  3.     ApplyFormatInEditMode="True" CalendarStyle="Winter" />               
  4. < asp:BoundField DataField="BirthDate" HeaderText="BirthDate"    
  5.     SortExpression="BirthDate" DataFormatString="{0:d}"    
  6.     ApplyFormatInEditMode="True" ReadOnly="true" />  

執行程式,在編輯資料列時,TBDateField 就會以 TDateEdit 控制項來進行編輯。

image

使用 TDateEdit 編輯欄位值後,按「更新」鈕,資料就會被寫回資料庫。

image

 

備註:本文同步發佈於「第一屆iT邦幫忙鐵人賽」,如果你覺得這篇文章對您有幫助,記得連上去推鑒此文增加人氣 ^^ 
http://ithelp.ithome.com.tw/question/10013083
http://ithelp.ithome.com.tw/question/10013091