摘要

在「讓 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 的定義轉換為欄位值。

 

  1. Imports System.Collections.Specialized   
  2. Imports System.ComponentModel   
  3. Imports System.Web   
  4. Imports System.Web.UI   
  5. Imports System.Web.UI.WebControls   
  6.   
  7. Namespace WebControls   
  8.     < _   
  9.     Description("核取方塊欄位") _   
  10.     > _   
  11.     Public Class TBCheckBoxField   
  12.         Inherits CheckBoxField   
  13.   
  14.         Private FDefineValue As String = String.Empty   
  15.   
  16.         '''    
  17.         ''' 布林值轉換定義,格式為 "True/False"。   
  18.         '''    
  19.         '''    
  20.         ''' 當設定為 "T/F" 時,表示 T 為 True,F 為 False。   
  21.         ''' 當設定為 "T/*" 時,表示 T 為 True,其他為 False。   
  22.         '''     
  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.         '''    
  33.         ''' 解析布林值轉換定義。   
  34.         '''    
  35.         ''' 布林值轉換定義。   
  36.         ''' True 的對應值。   
  37.         ''' False 的對應值。   
  38.         Private Sub ParserDefineValue(ByVal DefineValue As StringByRef TrueValue As StringByRef 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.         '''    
  50.         ''' 欄位值依 DefineValue 的定義轉換為布林值。   
  51.         '''    
  52.         ''' 欄位值。   
  53.         Private Function ValueToBoolean(ByVal Value As ObjectAs 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.         '''    
  71.         ''' 布林值依 DefineValue 的定義轉換為欄位值。   
  72.         '''    
  73.         ''' 布林值。   
  74.         Private Function BooleanToValue(ByVal Value As BooleanAs 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.         '''    
  91.         ''' 將欄位值繫結至 TBCheckBoxField 物件中的核取方塊。    
  92.         '''    
  93.         ''' 作用的控制項。   
  94.         ''' 事件引數。   
  95.         Protected Overrides Sub OnDataBindField(ByVal sender As ObjectByVal 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.         '''    
  126.         ''' 使用指定 DataControlFieldCell 物件的值填入指定的 System.Collections.IDictionary 物件。    
  127.         '''    
  128.         ''' 用於儲存指定儲存格的值。   
  129.         ''' 包含要擷取值的儲存格。   
  130.         ''' 資料列的狀態。   
  131.         ''' true 表示包含唯讀欄位的值,否則為 false。   
  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 NothingAndAlso (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 NothingThen  
  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  
  160. End Namespace  

測試程式

我們使用 Northwind 資料庫的 Employees 資料表做測試,在 Employees 加入一個 Checked 欄位,資料型別為 nvarchar(1),欄位值為 "是" 或 "否";我們使用 TBCheckBoxField 來繫結 Checked 欄位做測試。

我們分別使用 BoundField 及 TBCheckBoxField 同時繫結 Checked 欄位,BoundField 為唯讀供顯示對照使用,而 TBCheckBoxField 則提供編輯 Checked 欄位值,其中設定 TBCheckBoxField.DefineValue="是/否"。

  1. <asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" DataSourceID="SqlDataSource1"  
  2.     EmptyDataText="沒有資料錄可顯示。" AllowPaging="True" DataKeyNames="EmployeeID">  
  3.     <Columns>  
  4.         <asp:CommandField ShowEditButton="True" />  
  5.         <asp:BoundField DataField="EmployeeID" HeaderText="EmployeeID" InsertVisible="False"  
  6.             ReadOnly="True" SortExpression="EmployeeID" />  
  7.         <asp:BoundField DataField="LastName" HeaderText="LastName" SortExpression="LastName" />  
  8.         <asp:BoundField DataField="FirstName" HeaderText="FirstName" SortExpression="FirstName" />  
  9.         <asp:BoundField DataField="Checked" HeaderText="Checked" SortExpression="Checked" ReadOnly="True" />  
  10.         <bee:TBCheckBoxField DataField="Checked" HeaderText="Checked(TBCheckBoxField)" SortExpression="Checked" DefineValue="是/否" />  
  11.     Columns>  
  12. asp:GridView>  

執行程式,瀏覽資料的畫面如下。

image

按下「編輯」鈕進入編輯狀態,使用 TBCheckBoxField 來編輯 Checked 欄位。

image

按下「更新」鈕後,會發現 Checked 欄位值被正常更新了。

image