摘要
在「讓 CheckBoxField 繫結非布林值(0 或 1)欄位」一文中有介紹了如何修改 CheckFieldBox 去繫結 0 或 1 的非布林值,其作法是將非布林直接使用 CBool 函式將欄位值強制轉型為布林值。 不過有時繫結的欄位值並無法直接使用 CBool 轉型為布林值,例如 "T/F"、"是/否" 之類的資料,若希望使用 CheckBoxField 來顯示就比較麻煩,一般的作法都是轉為 TemplateField,自行撰寫資料繫結的函式,而且只能支援單向繫結。在本文中我們將直接改寫 CheckBoxField 類別,讓 CheckBoxField 可以直接雙向繫結 "T/F" 或 "是/否" 之類的資料。
擴展 CheckBoxField 類別
我們繼承 CheckBoxField 命名為 TBCheckBoxField,新增 DefineValue 屬性,用來做布林值轉換定義(格式為 "True/False");若設定 DefineValue="是/否",即欄位值為 "是" 對應到 True,而 "否" 對應到 False。
當讀取欄位值要繫結至控制項時會引發 OnDataBindField 方法;故覆寫 OnDataBindField 方法,判斷若有設定 DefineValue 屬性,則利用 ValueToBoolean 方法將欄位值依 DefineValue 的定義轉換為布林值。例如將 "男/女" 轉為 "True/False",再與控制項做繫結。
當要寫入資料時會由控制項擷取出目前的欄位值,此時會引發 ExtractValuesFromCell 方法;故覆寫 ExtractValuesFromCell 方法,此時會擷取 CheckBoxField 內含的 CheckBox 控制項的 Checked 屬性值(布林值),若有設定 DefineValue 屬性時,會利用 BooleanToValue 方法將布林值依 DefineValue 的定義轉換為欄位值。
- Imports System.Collections.Specialized
- Imports System.ComponentModel
- Imports System.Web
- Imports System.Web.UI
- Imports System.Web.UI.WebControls
- Namespace WebControls
- < _
- Description("核取方塊欄位") _
- > _
- Public Class TBCheckBoxField
- Inherits CheckBoxField
- Private FDefineValue As String = String.Empty
- '''
- ''' 布林值轉換定義,格式為 "True/False"。
- '''
- '''
- ''' 當設定為 "T/F" 時,表示 T 為 True,F 為 False。
- ''' 當設定為 "T/*" 時,表示 T 為 True,其他為 False。
- '''
- Public Property DefineValue() As String
- Get
- Return FDefineValue
- End Get
- Set(ByVal value As String)
- FDefineValue = value
- End Set
- End Property
- '''
- ''' 解析布林值轉換定義。
- '''
- ''' 布林值轉換定義。
- ''' True 的對應值。
- ''' False 的對應值。
- Private Sub ParserDefineValue(ByVal DefineValue As String, ByRef TrueValue As String, ByRef FalseValue As String)
- Dim oParts() As String
- oParts = Split(Me.DefineValue, "/")
- If oParts.Length <> 2 Then
- Throw New HttpException("DefineValue 格式錯誤")
- End If
- TrueValue = oParts(0)
- FalseValue = oParts(1)
- End Sub
- '''
- ''' 欄位值依 DefineValue 的定義轉換為布林值。
- '''
- ''' 欄位值。
- Private Function ValueToBoolean(ByVal Value As Object) As Boolean
- Dim sFieldValue As String
- Dim sTrueValue As String
- Dim sFalseValue As String
- sFieldValue = CStr(Value)
- sTrueValue = String.Empty
- sFalseValue = String.Empty
- ParserDefineValue(Me.DefineValue, sTrueValue, sFalseValue)
- If sFieldValue = sTrueValue Then
- Return True
- Else
- Return False
- End If
- End Function
- '''
- ''' 布林值依 DefineValue 的定義轉換為欄位值。
- '''
- ''' 布林值。
- Private Function BooleanToValue(ByVal Value As Boolean) As Object
- Dim sTrueValue As String
- Dim sFalseValue As String
- sTrueValue = String.Empty
- sFalseValue = String.Empty
- ParserDefineValue(Me.DefineValue, sTrueValue, sFalseValue)
- If Value Then
- Return sTrueValue
- Else
- Return sFalseValue
- End If
- End Function
- '''
- ''' 將欄位值繫結至 TBCheckBoxField 物件中的核取方塊。
- '''
- ''' 作用的控制項。
- ''' 事件引數。
- Protected Overrides Sub OnDataBindField(ByVal sender As Object, ByVal e As EventArgs)
- Dim oControl As Control = DirectCast(sender, Control)
- Dim oNamingContainer As Control = oControl.NamingContainer
- Dim oFieldValue As Object = Me.GetValue(oNamingContainer)
- If Not TypeOf oControl Is CheckBox Then
- Throw New HttpException("繫結的控制項非核取方塊")
- End If
- If IsDBNull(oFieldValue) Then
- DirectCast(oControl, CheckBox).Checked = False
- ElseIf TypeOf oFieldValue Is Boolean Then
- DirectCast(oControl, CheckBox).Checked = CBool(oFieldValue)
- Else
- If Not Me.DesignMode Then
- Try
- If Me.DefineValue <> String.Empty Then
- DirectCast(oControl, CheckBox).Checked = ValueToBoolean(oFieldValue)
- Else
- DirectCast(oControl, CheckBox).Checked = CBool(oFieldValue)
- End If
- Catch exception As FormatException
- Throw New HttpException("無法將值轉為布林值", exception)
- End Try
- End If
- End If
- DirectCast(oControl, CheckBox).Text = Me.Text
- End Sub
- '''
- ''' 使用指定 DataControlFieldCell 物件的值填入指定的 System.Collections.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 oFieldValue As Object = Nothing
- If (Cell.Controls.Count > 0) Then
- oControl = Cell.Controls.Item(0)
- Dim oCheckBox As CheckBox = TryCast(oControl, CheckBox)
- If ((Not oCheckBox Is Nothing) AndAlso (IncludeReadOnly OrElse oCheckBox.Enabled)) Then
- If Me.DefineValue = String.Empty Then
- oFieldValue = oCheckBox.Checked
- Else
- oFieldValue = BooleanToValue(oCheckBox.Checked)
- End If
- End If
- End If
- If (Not oFieldValue Is Nothing) Then
- If Dictionary.Contains(sDataField) Then
- Dictionary.Item(sDataField) = oFieldValue
- Else
- Dictionary.Add(sDataField, oFieldValue)
- End If
- End If
- End Sub
- End Class
- End Namespace
測試程式
我們使用 Northwind 資料庫的 Employees 資料表做測試,在 Employees 加入一個 Checked 欄位,資料型別為 nvarchar(1),欄位值為 "是" 或 "否";我們使用 TBCheckBoxField 來繫結 Checked 欄位做測試。
我們分別使用 BoundField 及 TBCheckBoxField 同時繫結 Checked 欄位,BoundField 為唯讀供顯示對照使用,而 TBCheckBoxField 則提供編輯 Checked 欄位值,其中設定 TBCheckBoxField.DefineValue="是/否"。
- <asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" DataSourceID="SqlDataSource1"
- EmptyDataText="沒有資料錄可顯示。" AllowPaging="True" DataKeyNames="EmployeeID">
- <Columns>
- <asp:CommandField ShowEditButton="True" />
- <asp:BoundField DataField="EmployeeID" HeaderText="EmployeeID" InsertVisible="False"
- ReadOnly="True" SortExpression="EmployeeID" />
- <asp:BoundField DataField="LastName" HeaderText="LastName" SortExpression="LastName" />
- <asp:BoundField DataField="FirstName" HeaderText="FirstName" SortExpression="FirstName" />
- <asp:BoundField DataField="Checked" HeaderText="Checked" SortExpression="Checked" ReadOnly="True" />
- <bee:TBCheckBoxField DataField="Checked" HeaderText="Checked(TBCheckBoxField)" SortExpression="Checked" DefineValue="是/否" />
- Columns>
- asp:GridView>
執行程式,瀏覽資料的畫面如下。
按下「編輯」鈕進入編輯狀態,使用 TBCheckBoxField 來編輯 Checked 欄位。
按下「更新」鈕後,會發現 Checked 欄位值被正常更新了。
