前二篇文章介绍了自订 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