初期状態のコンボボックスセルでは、普通のコントロールのように適当なクラスをアイテムに利用していると、
フォーカスが遷移するあたりで例外がサックリと発生してしまうと思う。逆に言えば、ここをクリアするとDataGridViewでも
コンボボックスは普段通り利用可能になるというコトで。じゃあ何が問題で例外が発生しているかというと。
- コンボボックスの編集結果をセルに表示する
- セルに表示されている値から編集時のコンボボックスを調整する
初期状態で足りないのはこの2点。実際には上の「セルに表示する」ってのは、致命傷というほどじゃなくそのままいこうと思えば
そのまま行ってしまえる程度なんだよね。なので本当に問題なのは下の「セルから編集時のコンボボックスを調整」する方。
ここが初期状態のコンボボックスセル関連で不足している部分。アンバウンドだから発生するんだよね、ここは。
じゃあこれをどこで行えばいいか、と言われると。
「編集の前段階」なのでDataGridViewCellで行う処理だ、ということになるんだよね。実際には
DataGridViewCell.ParseFormattedValue メソッド (System.Windows.Forms)
というメソッドがあるのでここで行うことに。実は違う方法もあるんだけど、それはまた別の機会かな。
TypeConverterを利用する方法は結構難しいところがあるので。
''' <summary>表示用に書式設定された値を実際のセル値に変換します</summary>
Public Overrides Function ParseFormattedValue( _
ByVal formattedValue As Object, _
ByVal cellStyle As System.Windows.Forms.DataGridViewCellStyle, _
ByVal formattedValueTypeConverter As System.ComponentModel.TypeConverter, _
ByVal valueTypeConverter As System.ComponentModel.TypeConverter) As ObjectDim columnEdit As ExComboItemColumn _
= TryCast(Me.DataGridView.Columns(ColumnIndex), ExComboItemColumn)
If columnEdit Is Nothing Then Return NothingFor Each cellItem As Object In columnEdit.Items
If cellItem.ToString = formattedValue.ToString Then Return cellItem
Next
Return Nothing
End Function
大体こんな感じ。ここだけみると「あれ?」という感じになるんだけど、実はカラム側で下準備が一つある。
''' <summary>コンストラクタ</summary>
Public Sub New()
MyBase.New()
Me.CellTemplate = New ExComboItemCell
Me.ValueType = GetType(ComboItem)
End Sub
カラム側のコンストラクタでValueTypeプロパティにComboItemクラスのTypeを設定しているところがある。
こうしておくと、このカラムではComboItemクラスのインスタンスを値として扱うよ、という宣言になるのよ。
では最終的なソースを。
''' <summary>独自クラスを利用できるコンボボックス型DataGridViewCell</summary>
Public Class ExComboItemCell
Inherits System.Windows.Forms.DataGridViewComboBoxCell''' <summary>
''' EditTypeプロパティ
''' </summary>
''' <value>ExComboItemEditingControlのType</value>
''' <remarks>ExComboItemEditingControlを返却する</remarks>
Public Overrides ReadOnly Property EditType() As System.Type
Get
Return GetType(ExComboItemEditingControl)
End Get
End Property''' <summary>入力コントロール初期化</summary>
Public Overrides Sub InitializeEditingControl( _
ByVal rowIndex As Integer, _
ByVal initialFormattedValue As Object, _
ByVal dataGridViewCellStyle As System.Windows.Forms.DataGridViewCellStyle)MyBase.InitializeEditingControl(rowIndex, initialFormattedValue, dataGridViewCellStyle)
Dim columnEdit As ExComboItemColumn _
= DirectCast(Me.DataGridView.Columns(ColumnIndex), ExComboItemColumn)
If columnEdit IsNot Nothing ThenEnd If
End Sub''' <summary>クローンの生成</summary>
Public Overrides Function Clone() As Object
'プロパティのクローン作成
Dim cloneCell As ExComboItemCell = DirectCast(MyBase.Clone, ExComboItemCell)Return cloneCell
End Function''' <summary>表示用に書式設定された値を実際のセル値に変換します</summary>
Public Overrides Function ParseFormattedValue( _
ByVal formattedValue As Object, _
ByVal cellStyle As System.Windows.Forms.DataGridViewCellStyle, _
ByVal formattedValueTypeConverter As System.ComponentModel.TypeConverter, _
ByVal valueTypeConverter As System.ComponentModel.TypeConverter) As ObjectDim columnEdit As ExComboItemColumn _
= TryCast(Me.DataGridView.Columns(ColumnIndex), ExComboItemColumn)
If columnEdit Is Nothing Then Return NothingFor Each cellItem As Object In columnEdit.Items
If cellItem.ToString = formattedValue.ToString Then Return cellItem
Next
Return Nothing
End Function''' <summary>表示用に書式指定済みのセル値を取得します</summary>
Protected Overrides Function GetFormattedValue( _
ByVal value As Object, _
ByVal rowIndex As Integer, _
ByRef cellStyle As System.Windows.Forms.DataGridViewCellStyle, _
ByVal valueTypeConverter As System.ComponentModel.TypeConverter, _
ByVal formattedValueTypeConverter As System.ComponentModel.TypeConverter, _
ByVal context As System.Windows.Forms.DataGridViewDataErrorContexts) As ObjectIf value Is Nothing Then Return ""
Return value.ToString
End Function
End Class''' <summary>独自クラスを利用できるコンボボックス型DataGridViewColumn</summary>
<System.Diagnostics.DebuggerStepThrough()> _
Public Class ExComboItemColumn
Inherits System.Windows.Forms.DataGridViewComboBoxColumn''' <summary>コンストラクタ</summary>
Public Sub New()
MyBase.New()
Me.CellTemplate = New ExComboItemCell
Me.ValueType = GetType(ComboItem)
End Sub''' <summary>CellTemplateプロパティ</summary>
''' <exception cref="ArgumentException">ExComboItemCell以外が指定されました</exception>
Public Overrides Property CellTemplate() As System.Windows.Forms.DataGridViewCell
Get
Return MyBase.CellTemplate
End Get
Set(ByVal value As System.Windows.Forms.DataGridViewCell)
If Not (TypeOf value Is ExComboItemCell) Then
Throw New ArgumentException("CellTemplateプロパティはExComboItemCellを設定する必要があります。")
End If
MyBase.CellTemplate = value
End Set
End PropertyEnd Class
''' <summary>独自クラスを利用できるコンボボックス型DataGridViewEditingControl</summary>
<System.ComponentModel.DesignTimeVisible(False)> _
<System.ComponentModel.ToolboxItem(False)> _
Public Class ExComboItemEditingControl
Inherits System.Windows.Forms.DataGridViewComboBoxEditingControl''' <summary>Enterイベント</summary>
Protected Overrides Sub OnEnter(ByVal e As System.EventArgs)Dim nowIndex As Integer = Me.SelectedIndex
Dim editColumn As ExComboItemColumn _
= TryCast(Me.EditingControlDataGridView.Columns(Me.EditingControlDataGridView.CurrentCell.ColumnIndex), ExComboItemColumn)
If editColumn Is Nothing Then Return
Me.Items.Clear()
For Each columnItem As Object In editColumn.Items
Me.Items.Add(columnItem)
Next
Me.SelectedIndex = nowIndex
MyBase.OnEnter(e)End Sub
End Class
ポイントは「面倒だからもともとのComboBoxセル関係を継承してしまう」というところ。
あと、これは微妙なんだけどExComboItemEditingControlのEnter時にアイテムの再設定を行っているんだけど、
これはセルのInitializeEditingControlメソッドで行うのがベターな気がするね。
0 件のコメント:
コメントを投稿