摘要
在「让 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 的定义转换为字段值。
在「让 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 的定义转换为字段值。
1Imports System.Collections.Specialized
2Imports System.ComponentModel
3Imports System.Web
4Imports System.Web.UI
5Imports System.Web.UI.WebControls
6
7Namespace WebControls
8 < _
9 Description("复选框字段") _
10 > _
11 Public Class TBCheckBoxField
12 Inherits CheckBoxField
13
14 Private FDefineValue As String = String.Empty
15
16 ''' <summary>
17 ''' 布尔值转换定义,格式为 "True/False"。
18 ''' </summary>
19 ''' <returns>
20 ''' 当设定为 "T/F" 时,表示 T 为 True,F 为 False。
21 ''' 当设定为 "T/*" 时,表示 T 为 True,其它为 False。
22 ''' </returns>
23 Public Property DefineValue() As String
24 Get
25 Return FDefineValue
26 End Get
27 Set(ByVal value As String)
28 FDefineValue = value
29 End Set
30 End Property
31
32 ''' <summary>
33 ''' 解析布尔值转换定义。
34 ''' </summary>
35 ''' <param name="DefineValue">布尔值转换定义。</param>
36 ''' <param name="TrueValue">True 的对应值。</param>
37 ''' <param name="FalseValue">False 的对应值。</param>
38 Private Sub ParserDefineValue(ByVal DefineValue As String, ByRef TrueValue As String, ByRef FalseValue As String)
39 Dim oParts() As String
40
41 oParts = Split(Me.DefineValue, "/")
42 If oParts.Length <> 2 Then
43 Throw New HttpException("DefineValue 格式错误")
44 End If
45 TrueValue = oParts(0)
46 FalseValue = oParts(1)
47 End Sub
48
49 ''' <summary>
50 ''' 字段值依 DefineValue 的定义转换为布尔值。
51 ''' </summary>
52 ''' <param name="Value">字段值。</param>
53 Private Function ValueToBoolean(ByVal Value As Object) As Boolean
54 Dim sFieldValue As String
55 Dim sTrueValue As String
56 Dim sFalseValue As String
57
58 sFieldValue = CStr(Value)
59 sTrueValue = String.Empty
60 sFalseValue = String.Empty
61 ParserDefineValue(Me.DefineValue, sTrueValue, sFalseValue)
62
63 If sFieldValue = sTrueValue Then
64 Return True
65 Else
66 Return False
67 End If
68 End Function
69
70 ''' <summary>
71 ''' 布尔值依 DefineValue 的定义转换为字段值。
72 ''' </summary>
73 ''' <param name="Value">布尔值。</param>
74 Private Function BooleanToValue(ByVal Value As Boolean) As Object
75 Dim sTrueValue As String
76 Dim sFalseValue As String
77
78 sTrueValue = String.Empty
79 sFalseValue = String.Empty
80 ParserDefineValue(Me.DefineValue, sTrueValue, sFalseValue)
81
82 If Value Then
83 Return sTrueValue
84 Else
85 Return sFalseValue
86 End If
87 End Function
88
89
90 ''' <summary>
91 ''' 将字段值系结至 TBCheckBoxField 对象中的复选框。
92 ''' </summary>
93 ''' <param name="sender">作用的控件。</param>
94 ''' <param name="e">事件自变量。</param>
95 Protected Overrides Sub OnDataBindField(ByVal sender As Object, ByVal e As EventArgs)
96 Dim oControl As Control = DirectCast(sender, Control)
97 Dim oNamingContainer As Control = oControl.NamingContainer
98 Dim oFieldValue As Object = Me.GetValue(oNamingContainer)
99
100 If Not TypeOf oControl Is CheckBox Then
101 Throw New HttpException("系结的控件非复选框")
102 End If
103
104 If IsDBNull(oFieldValue) Then
105 DirectCast(oControl, CheckBox).Checked = False
106 ElseIf TypeOf oFieldValue Is Boolean Then
107 DirectCast(oControl, CheckBox).Checked = CBool(oFieldValue)
108 Else
109 If Not Me.DesignMode Then
110 Try
111 If Me.DefineValue <> String.Empty Then
112 DirectCast(oControl, CheckBox).Checked = ValueToBoolean(oFieldValue)
113 Else
114 DirectCast(oControl, CheckBox).Checked = CBool(oFieldValue)
115 End If
116 Catch exception As FormatException
117 Throw New HttpException("无法将值转为布尔值", exception)
118 End Try
119 End If
120 End If
121
122 DirectCast(oControl, CheckBox).Text = Me.Text
123 End Sub
124
125 ''' <summary>
126 ''' 使用指定 DataControlFieldCell 对象的值填入指定的 System.Collections.IDictionary 物件。
127 ''' </summary>
128 ''' <param name="dictionary">用于储存指定储存格的值。</param>
129 ''' <param name="cell">包含要撷取值的储存格。</param>
130 ''' <param name="rowState">数据列的状态。</param>
131 ''' <param name="includeReadOnly">true 表示包含只读字段的值,否则为 false。</param>
132 Public Overrides Sub ExtractValuesFromCell(ByVal Dictionary As IOrderedDictionary, ByVal Cell As DataControlFieldCell, _
133 ByVal RowState As DataControlRowState, ByVal IncludeReadOnly As Boolean)
134 Dim oControl As Control = Nothing
135 Dim sDataField As String = Me.DataField
136 Dim oFieldValue As Object = Nothing
137
138 If (Cell.Controls.Count > 0) Then
139 oControl = Cell.Controls.Item(0)
140 Dim oCheckBox As CheckBox = TryCast(oControl, CheckBox)
141 If ((Not oCheckBox Is Nothing) AndAlso (IncludeReadOnly OrElse oCheckBox.Enabled)) Then
142 If Me.DefineValue = String.Empty Then
143 oFieldValue = oCheckBox.Checked
144 Else
145 oFieldValue = BooleanToValue(oCheckBox.Checked)
146 End If
147 End If
148 End If
149
150 If (Not oFieldValue Is Nothing) Then
151 If Dictionary.Contains(sDataField) Then
152 Dictionary.Item(sDataField) = oFieldValue
153 Else
154 Dictionary.Add(sDataField, oFieldValue)
155 End If
156 End If
157 End Sub
158
159 End Class
160End Namespace
2Imports System.ComponentModel
3Imports System.Web
4Imports System.Web.UI
5Imports System.Web.UI.WebControls
6
7Namespace WebControls
8 < _
9 Description("复选框字段") _
10 > _
11 Public Class TBCheckBoxField
12 Inherits CheckBoxField
13
14 Private FDefineValue As String = String.Empty
15
16 ''' <summary>
17 ''' 布尔值转换定义,格式为 "True/False"。
18 ''' </summary>
19 ''' <returns>
20 ''' 当设定为 "T/F" 时,表示 T 为 True,F 为 False。
21 ''' 当设定为 "T/*" 时,表示 T 为 True,其它为 False。
22 ''' </returns>
23 Public Property DefineValue() As String
24 Get
25 Return FDefineValue
26 End Get
27 Set(ByVal value As String)
28 FDefineValue = value
29 End Set
30 End Property
31
32 ''' <summary>
33 ''' 解析布尔值转换定义。
34 ''' </summary>
35 ''' <param name="DefineValue">布尔值转换定义。</param>
36 ''' <param name="TrueValue">True 的对应值。</param>
37 ''' <param name="FalseValue">False 的对应值。</param>
38 Private Sub ParserDefineValue(ByVal DefineValue As String, ByRef TrueValue As String, ByRef FalseValue As String)
39 Dim oParts() As String
40
41 oParts = Split(Me.DefineValue, "/")
42 If oParts.Length <> 2 Then
43 Throw New HttpException("DefineValue 格式错误")
44 End If
45 TrueValue = oParts(0)
46 FalseValue = oParts(1)
47 End Sub
48
49 ''' <summary>
50 ''' 字段值依 DefineValue 的定义转换为布尔值。
51 ''' </summary>
52 ''' <param name="Value">字段值。</param>
53 Private Function ValueToBoolean(ByVal Value As Object) As Boolean
54 Dim sFieldValue As String
55 Dim sTrueValue As String
56 Dim sFalseValue As String
57
58 sFieldValue = CStr(Value)
59 sTrueValue = String.Empty
60 sFalseValue = String.Empty
61 ParserDefineValue(Me.DefineValue, sTrueValue, sFalseValue)
62
63 If sFieldValue = sTrueValue Then
64 Return True
65 Else
66 Return False
67 End If
68 End Function
69
70 ''' <summary>
71 ''' 布尔值依 DefineValue 的定义转换为字段值。
72 ''' </summary>
73 ''' <param name="Value">布尔值。</param>
74 Private Function BooleanToValue(ByVal Value As Boolean) As Object
75 Dim sTrueValue As String
76 Dim sFalseValue As String
77
78 sTrueValue = String.Empty
79 sFalseValue = String.Empty
80 ParserDefineValue(Me.DefineValue, sTrueValue, sFalseValue)
81
82 If Value Then
83 Return sTrueValue
84 Else
85 Return sFalseValue
86 End If
87 End Function
88
89
90 ''' <summary>
91 ''' 将字段值系结至 TBCheckBoxField 对象中的复选框。
92 ''' </summary>
93 ''' <param name="sender">作用的控件。</param>
94 ''' <param name="e">事件自变量。</param>
95 Protected Overrides Sub OnDataBindField(ByVal sender As Object, ByVal e As EventArgs)
96 Dim oControl As Control = DirectCast(sender, Control)
97 Dim oNamingContainer As Control = oControl.NamingContainer
98 Dim oFieldValue As Object = Me.GetValue(oNamingContainer)
99
100 If Not TypeOf oControl Is CheckBox Then
101 Throw New HttpException("系结的控件非复选框")
102 End If
103
104 If IsDBNull(oFieldValue) Then
105 DirectCast(oControl, CheckBox).Checked = False
106 ElseIf TypeOf oFieldValue Is Boolean Then
107 DirectCast(oControl, CheckBox).Checked = CBool(oFieldValue)
108 Else
109 If Not Me.DesignMode Then
110 Try
111 If Me.DefineValue <> String.Empty Then
112 DirectCast(oControl, CheckBox).Checked = ValueToBoolean(oFieldValue)
113 Else
114 DirectCast(oControl, CheckBox).Checked = CBool(oFieldValue)
115 End If
116 Catch exception As FormatException
117 Throw New HttpException("无法将值转为布尔值", exception)
118 End Try
119 End If
120 End If
121
122 DirectCast(oControl, CheckBox).Text = Me.Text
123 End Sub
124
125 ''' <summary>
126 ''' 使用指定 DataControlFieldCell 对象的值填入指定的 System.Collections.IDictionary 物件。
127 ''' </summary>
128 ''' <param name="dictionary">用于储存指定储存格的值。</param>
129 ''' <param name="cell">包含要撷取值的储存格。</param>
130 ''' <param name="rowState">数据列的状态。</param>
131 ''' <param name="includeReadOnly">true 表示包含只读字段的值,否则为 false。</param>
132 Public Overrides Sub ExtractValuesFromCell(ByVal Dictionary As IOrderedDictionary, ByVal Cell As DataControlFieldCell, _
133 ByVal RowState As DataControlRowState, ByVal IncludeReadOnly As Boolean)
134 Dim oControl As Control = Nothing
135 Dim sDataField As String = Me.DataField
136 Dim oFieldValue As Object = Nothing
137
138 If (Cell.Controls.Count > 0) Then
139 oControl = Cell.Controls.Item(0)
140 Dim oCheckBox As CheckBox = TryCast(oControl, CheckBox)
141 If ((Not oCheckBox Is Nothing) AndAlso (IncludeReadOnly OrElse oCheckBox.Enabled)) Then
142 If Me.DefineValue = String.Empty Then
143 oFieldValue = oCheckBox.Checked
144 Else
145 oFieldValue = BooleanToValue(oCheckBox.Checked)
146 End If
147 End If
148 End If
149
150 If (Not oFieldValue Is Nothing) Then
151 If Dictionary.Contains(sDataField) Then
152 Dictionary.Item(sDataField) = oFieldValue
153 Else
154 Dictionary.Add(sDataField, oFieldValue)
155 End If
156 End If
157 End Sub
158
159 End Class
160End Namespace
测试程序
我们使用 Northwind 数据库的 Employees 数据表做测试,在 Employees 加入一个 Checked 字段,数据型别为 nvarchar(1),字段值为 "是" 或 "否";我们使用 TBCheckBoxField 来系结 Checked 字段做测试。
我们分别使用 BoundField 及 TBCheckBoxField 同时系结 Checked 字段,BoundField 为只读供显示对照使用,而 TBCheckBoxField 则提供编辑 Checked 字段值,其中设定 TBCheckBoxField.DefineValue="是/否"。
执行程序,浏览数据的画面如下。
按下「编辑」钮进入编辑状态,使用 TBCheckBoxField 来编辑 Checked 字段。
按下「更新」钮后,会发现 Checked 字段值被正常更新了。