フィールドプロバイダを作成することで、独自の形式のフィールドを利 用できるようになります。このドキュメントでは例としていくつかの フィールドプロバイダを作成していきます。
フィールドに画像を表示してみましょう。
以下の画像を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で返された文字列を描画するのに必 要なサイズを返すようになっています。