フィールドプロバイダの作成

フィールドプロバイダを作成することで、独自の形式のフィールドを利 用できるようになります。このドキュメントでは例としていくつかの フィールドプロバイダを作成していきます。

画像を表示するフィールドプロバイダ

フィールドに画像を表示してみましょう。

以下の画像をMy.Resource.sampleという名前でリソースに登録しておき ます。

描画を行うRenderメソッドをオーバーライドしたフィールドプロバイダ を作成します。RenderメソッドにはGraphicsオブジェクト、フィールド オブジェクト、フィールドを描画すべき矩形、偶数行か奇数行かが渡さ れます。この例では単にrect全体に画像を描画しています。

    Class CImageFieldProvider
        Inherits CFieldProvider
        Public Overrides Sub Render(ByVal g As System.Drawing.Graphics, _
                                    ByVal field As systembase.table.UTable.CField, _
                                    ByVal rect As System.Drawing.Rectangle, _
                                    ByVal alter As Boolean)
            g.DrawImage(My.Resources.sample, rect)
        End Sub
    End Class

このフィールドプロバイダを利用するコードは以下のようになります。

        Dim r As UTable.CRecord = Me.Table.Content.AddRecord
        With New CFieldBuilder
            With r.AddField(0, New CImageFieldProvider, .Next)
                .Row.Size = 100
                .Col.Size = 100
            End With            
        End With

数値を表示するフィールドプロバイダ

カンマ編集、右寄せのフィールドを作成してみましょう。

フィールドプロバイダは以下のようになります。ValueFormatで、表示す るデータのフォーマットを行います。また、Settingメソッドでこのフィー ルドが持つデフォルトのプロパティを指定できます。

    Class CNumberFieldProvider
        Inherits CFieldProvider
        Public Overrides Function ValueFormat(ByVal v As Object) As String
            Return Format(v, "#,###")
        End Function
        Public Overrides Function Setting() As systembase.table.UTable.CSetting
            Dim s As New UTable.CSetting
            s.HorizontalAlignment = systembase.table.UTable.CSetting.EHAlign.RIGHT
            Return s
        End Function        
    End Class

利用するコードは次のようになります。このフィールドはユーザからの 入力を受け付ける機能を持たないので、レコードが追加されると同時に 値を設定する例を紹介します。

        Dim rp As New UTable.CRecordProvider
        With New CFieldBuilder
            rp.AddField(0, New CNumberFieldProvider, .Next)
        End With
        Me.Table.Content.SetRecordProvider(rp)
        Me.Table.CreateCaption()

        Using Me.Table.UpdateBufferBlock
            Me.Table.Content.AddRecord().Fields(0).Value = 1
            Me.Table.Content.AddRecord().Fields(0).Value = 12
            Me.Table.Content.AddRecord().Fields(0).Value = 123
            Me.Table.Content.AddRecord().Fields(0).Value = 1234
            Me.Table.Content.AddRecord().Fields(0).Value = 12345
            Me.Table.Content.AddRecord().Fields(0).Value = 123456
            Me.Table.Content.AddRecord().Fields(0).Value = 1234567
            Me.Table.Content.AddRecord().Fields(0).Value = 12345678
            Me.Table.Content.AddRecord().Fields(0).Value = 123456789
            Me.Table.Content.AddRecord().Fields(0).Value = 1234567890
        End Using

日付入力を行うフィールドプロバイダ

次のようなことを実現しましょう。

エディタにDateTimePickerを用いて、日付を入力可能とします。この場 合、フィールドプロバイダを作成する前に、エディタを作成する必要が あります。

エディタの作成

UTable上で利用されるエディタは、IEditorインターフェースを実装して いなければなりません。ここでは、DateTimePickerを継承してIEditorを 実装します。

    Class CDateEditor
        Inherits DateTimePicker
        Implements IEditor

        ...

    End Class

IEditorの定義は以下のようになっています。

Public Interface IEditor
    Sub Initialize(ByVal field As UTable.CField)
    Sub Enter(ByVal key As Char, ByVal hIMC As Integer, ByVal clear As Boolean)
    Property Value() As Object
    Function RaiseValidate() As Boolean
    Function Control() As Control
    Event ProcessDialogKey(ByVal sender As Object, ByVal keyData As System.Windows.Forms.Keys, ByRef handled As Boolean)
    Event Leave(ByVal sender As Object, ByVal direction As String)    
    Event ValueChanged(ByVal sender As Object)
End Interface

各メンバがどのような意味を持っているかを理解するために、エディタ のライフサイクルについて説明します。

編集開始時

エディタが生成されると、Initializeメソッドが呼ばれます。ここで フィールドに設定されているフォントやアライメントなどのプロパティ をエディタに設定してください。

フィールド上にエディタを出現させるために、Controlにサイズと位置が 設定されます。通常、Controlメソッドは自分自身を返すように実装して ください。

編集モードに入る準備が全て終わると、Enterメソッドが呼ばれます。引 数として、キーボードから最初に入力された文字、またはImeのコンテキ ストハンドルが渡されるので、必要に応じてエディタに設定して下さい。

編集中

エディタのProcessDialogKeyメソッドをオーバーライドし、同名のイベ ントを発生させてください。UTableはこのイベントを受け取り、Enterキー などが押された際に編集モードを抜けて次のフィールドへ移動するなど の操作を行います。

エディタ内で値が変更されたら、ValueChangedイベントを発生させてく ださい。

編集終了時

多くの入力コントロールでは、ユーザによる入力が終了し、フォーカス が他のコントロールへ移ろうとすると、Validatingイベントが発生しま す。Validatingイベントハンドラでは入力内容の検証が行われ、もしキャ ンセルされるとフォーカスを移すことはできません。キャンセルされな かった場合は、Validatedイベントが発生し、そのコントロールからフォー カスを移すことができます。

UTableはエディタがControlのValidatingイベントを発生させると、 FieldValidatingイベントを発生させます。クライアントコードはこのイ ベントハンドラを書くことで、Validatingイベントのキャンセルを行う ことができます。キャンセルされずにValidatedイベントが発生すると、 UTableは編集モードを終了します。

編集モードが終わると、編集されたValueをフィールドに設定した後、エ ディタは破棄されます。次回の編集モード時に同じエディタのインスタ ンスが使いまわされることはありません。

編集モードが終了するケースには、エディタからフォーカスが失われる 以外に、次の2つの場合があります。

UTableは編集モードを終了させる必要が生じると、エディタの RaiseValidateメソッドを呼びます。RaiseValidateメソッドは、 ControlのValidatingイベントと(キャンセルされなかったら) Validatedイベントを呼ぶように実装してください。これにより、結果的 に編集モードが終了されることになります。

エディタはLeaveイベントを発生させることで、自発的に編集モードを抜 けることができます。UTableはLeaveイベントを受け取ると、エディタの RaiseValidateメソッドを呼びます。つまり、どのケースでも最終的には エディタがValidatedイベントを発生させることによって、編集モードは 終了されるという仕組みになっています。

実装

大まかな流れを確認したところで、実装をしていきましょう。

Initializeの実装は以下のようになります。DynamicSettingからは、そ のフィールドを含むコンテントやレコードなどから、最も優先度の高い プロパティ値を取得できます。つまり、そのフィールドにいま設定され るべき値を得ることができます。

        Public Sub Initialize(ByVal field As UTable.CField) Implements IEditor.Initialize
            With field.DynamicSetting
                Me.Font = .Font
            End With
        End Sub

Enterの実装は以下のようになります。keyは編集モードに入るときに入 力された文字で、hIMCはIMEのコンテキストハンドルです。エディタの内 容をいったんクリアする必要があるときは、clearにtrueが渡されます。 DateTimePickerは値をクリアすることもIMEによる入力も不可能なので、 単に入力フォーカスを移すだけとします。

        Public Sub _Enter(ByVal key As Char, ByVal hIMC As Integer, ByVal clear As Boolean) Implements IEditor.Enter            
            Me.Focus()
        End Sub

Controlの実装は以下のようになります。

        Public Function Control() As System.Windows.Forms.Control Implements systembase.table.IEditor.Control
            Return Me
        End Function

Valueの実装は以下のようになります。範囲外の値や不正な型の値が代入 されたときに(剣呑なやりかたですが)無視するようにしています。

        Public Property _Value() As Object Implements IEditor.Value
            Get
                Return Me.Value
            End Get
            Set(ByVal value As Object)
                Try
                    Me.Value = value
                Catch ex As Exception
                End Try
            End Set
        End Property

ProcessDialogKeyイベントとValueChangedイベントは次のように実装し ます。

        Public Event _ProcessDialogKey(ByVal sender As Object, ByVal keyData As System.Windows.Forms.Keys, ByRef handled As Boolean) Implements IEditor.ProcessDialogKey
        Public Event _Changed(ByVal sender As Object) Implements IEditor.Changed
	
        Protected Overrides Function ProcessDialogKey(ByVal keyData As System.Windows.Forms.Keys) As Boolean
            Dim handled As Boolean = False
            RaiseEvent _ProcessDialogKey(Me, keyData, handled)
            If handled Then
                Return True
            Else
                Return MyBase.ProcessDialogKey(keyData)
            End If
        End Function

        Private Sub CDateEditor_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.TextChanged
            RaiseEvent _Changed(Me)
        End Sub

RaiseValidateの実装は以下のようになります。このコードはほとんどの エディタでそのまま利用できます。

        Public Function RaiseValidate() As Boolean Implements IEditor.RaiseValidate
            Dim e As New System.ComponentModel.CancelEventArgs
            Me.OnValidating(e)
            If Not e.Cancel Then
                Me.OnValidated(System.EventArgs.Empty)
                Return True
            End If
            Return False
        End Function

Leaveの実装は以下のようになります。このエディタからは、Leaveイベ ントは発生しないものとします。

        Public Event _Leave(ByVal sender As Object, ByVal direction As String) Implements IEditor.Leave

フィールドプロバイダの作成

エディタの準備が整ったので、これを利用するフィールドプロバイダを 作成しましょう。コードは以下のようになります。

    Class CDateFieldProvider
        Inherits CFieldProvider
        Public Overrides Function Editor() As systembase.table.IEditor
            Return New CDateEditor
        End Function
        Public Overrides Function ValueFormat(ByVal v As Object) As String
            If TypeOf v Is DateTime Then
                Return CType(v, DateTime).ToString("yyyy/MM/dd")
            Else
                Return Nothing
            End If
        End Function
    End Class

Editorメソッドで、エディタのインスタンスを作成します。 ValueFormatメソッドで、フィールド上に値が表示される際のフォーマッ トを制御します。

これで、全ての準備が整いました。日付入力フィールドを利用するコー ドは次のようになります。

        Dim rp As New UTable.CRecordProvider
        With New CFieldBuilder
            rp.AddField(0, New CDateFieldProvider, .Next)
        End With
        Me.Table.Content.SetRecordProvider(rp)
        Me.Table.CreateCaption()

        Using Me.Table.UpdateBufferBlock
            For i As Integer = 0 To 10
                Me.Table.Content.AddRecord()
            Next
        End Using

コンボボックスのフィールドプロバイダ

コンボボックスフィールドを作成してみます。

エディタの作成

ComboBoxを継承して、IEditorを実装します。

    Class CComboEditor
        Inherits ComboBox
        Implements IEditor

        ...  

    End Class

実装すべき内容は、先ほど作成したCDateEditorとほぼ同じなので、異な る部分を中心に見ていきましょう。

Enterメソッドでは、clearが真ならばいったん内容を消します。また、 最初に入力された文字を設定します。

      Public Sub _Enter(ByVal key As Char, ByVal hIMC As Integer, ByVal clear As Boolean) Implements IEditor.Enter
            If clear Then
                Me.Text = Nothing
            End If
            Me.Focus()
            If key <> Nothing Then
                Me.Text = key
                Me.SelectionStart = 1
            End If
        End Sub

Valueプロパティは、Textに対する読み書きを行います。

        Public Property _Value() As Object Implements IEditor.Value
            Get
                Return Me.Text
            End Get
            Set(ByVal value As Object)
                Me.Text = value
            End Set
        End Property

左右両隣のフィールドへフォーカス移動できるように、以下の実装を行 います。カーソルが入力文字列の端にあるとき、隣のフィールドへ向か うカーソルキーが押された場合、Leaveイベントを発生することで編集モー ドを終了し、フォーカス移動を行います。Leaveイベントの引数として、 フォーカスの移動先を決めるコマンドを指定します。デフォルトでは、 [NEXT], [PREV], [UP], [DOWN], [LEFT], [RIGHT]が指定可能です。詳し くはキーボードオペレーションの作成 をご覧下さい。

        Protected Overrides Function IsInputKey(ByVal keyData As System.Windows.Forms.Keys) As Boolean
            Select Case keyData
                Case Keys.Left
                    If Me.SelectionLength = 0 And Me.SelectionStart = 0 Then
                        RaiseEvent _Leave(Me, "LEFT")
                        Return True
                    End If
                Case Keys.Right
                    If Me.SelectionLength = 0 And Me.SelectionStart = Me.Text.Length Then
                        RaiseEvent _Leave(Me, "RIGHT")
                        Return True
                    End If
            End Select
            Return MyBase.IsInputKey(keyData)
        End Function

フィールドプロバイダの作成

フィールドプロバイダの実装は以下のようになります。エディタが作成 された直後に呼ばれるEditorInitializeでデータソースの設定を行って います。

    Class CComboFieldProvider
        Inherits CFieldProvider

        Public DataSource As Object

        Public Sub New(ByVal dataSource As Object)
            MyBase.New()
            Me.DataSource = dataSource
        End Sub

        Public Overrides Function Editor() As systembase.table.IEditor
            Return New CComboEditor
        End Function

        Public Overrides Sub EditorInitialize(ByVal field As systembase.table.UTable.CField, ByVal editor As systembase.table.IEditor)
            With CType(editor, ComboBox)
                .DataSource = Me.DataSource
            End With
        End Sub

    End Class

利用するコードは以下のようになります。

        Dim rp As New UTable.CRecordProvider
        With New CFieldBuilder
            rp.AddField(0, New CComboFieldProvider(New String() {"AAA", "BBB", "CCC"}), .Next)
        End With
        Me.Table.Content.SetRecordProvider(rp)
        Me.Table.CreateCaption()

        Using Me.Table.UpdateBufferBlock
            For i As Integer = 0 To 10
                Me.Table.Content.AddRecord()
            Next
        End Using

フィールドプロバイダ詳細

これまでの例で、フィールドプロバイダのいくつかのオーバーライド可 能なメソッドについて断片的な説明を行ってきました。ここでは包括的 な説明を行います。

フィールドプロバイダを作るには、IFieldProviderインターフェースを 満たすクラスを作成すればよいのですが、特に問題がなければ、常に代 表的な実装であるCFieldProviderクラスを継承してください。

CFieldProviderが持つメンバについて、カテゴリごとに簡単に説明しま す。

CreateFieldメソッドは、その名のとおりフィールドのインスタンスを生 成するメソッドです。デフォルトではCField型のオブジェクトを生成し ますが、何か特殊なプロパティをフィールドに持たせたい場合などは、 フィールドのクラスを自分で作成して利用することができます。Editor メソッドはエディタのインスタンスを生成します。このメソッドが Nothingを返した場合、このフィールドを編集することはできなくなりま す。詳しくは前述の例を参照してください。

レコードプロバイダをコンテントに設定したとき、またはレコードプロ バイダを使わずにフィールドを作成したときにApplyTableが呼ばれます。 フィールドを作成したときはFieldInitialize、エディタを作成したとき は、EditorInitializeメソッドが呼ばれます。

Settingメソッドが返した設定内容は、このフィールドのデフォルトの設 定となります。Captionメソッドの戻り値は、UTable.CreateCaptionで作 成される見出しフィールドに利用されます。Enableが真のフィールドだ けが、フォーカスを得ることができます。IMEの入力を行う場合は、 ImeModeを必ずDisable以外に設定してください。BorderLineメンバによっ て、フィールドの枠線を描画するかどうかを制御できます。

Renderメソッドはフィールドの描画を行うメソッドで、デフォルトでは 次のことを行います。まず、RenderBackgroundメソッド(見出しならば CaptionBackGroundメソッド)で背景を描きます。次に、フィールドの Value値をFormatValueで表示形式の文字列に変換し、RenderValueメソッ ドで描画します。フィールドの描画を完全に制御したければRenderをオー バーライドしてください。それ以外の場合は、必要なメソッドだけをオー バーライドしてください。

GetAdjustsizeメソッドは、ユーザが見出しフィールドの境界線をダブル クリックしたときに行われる自動サイズ調整で使用されるサイズを返し ます。デフォルトでは、FormatValueで返された文字列を描画するのに必 要なサイズを返すようになっています。

目次へ戻る