.NET Frameworkのデータグリッド( System.Windows.Forms.DataGridView )はとても便利ですが、標準で提供されている機能だけではラジオボックスを使ったカラムを追加することができません。
こういう時は、DataGridViewTextBoxColumnクラスに、”✓”とブランクを組み合わせたり、DataGridViewCheckBoxColumnクラスを使ったりして、プログラムでラジオボタンっぽい動作をさせたりする力技的「なんちゃってラジオボタン」で回避したいところですが、DataGridViewクラスの列に、ラジオボタンの表示と編集が行えるクラスを書いてみました。
実行イメージは、下図のようになります。
データグリッドの「列の編集」でColumnTypeにDataGridViewRadioButtonColumnを割り当てると、ラジオボタンで表示されるようになります。
また、DataGridViewRadioButtonColumnクラスのGroupNameプロパティに適当な文字列を設定すると、ラジオボタンのグループ化が行われます。
グループ化されたラジオボタンは、グループの中でひとつだけが選択状態となります。
ラジオボタンの大きさは、DataGridViewCheckBoxColumnクラスに合わせて常に固定サイズで描画されるようにしています。
ボタンの大きさを変更したいときは、DataGridViewRadioButtonCellクラスの定数RADIO_SIZEを変更するか、Paintメソッドを修正してください。
(動作確認はVisual Studio 2013 Update 4で行いました。)
' This software is distributed under the license of NYSL. ' ( http://www.kmonos.net/nysl/ ) Imports System.ComponentModel ''' ''' ラジオボタンセル(DataGridViewRadioButtonCell)のホスト ''' Public Class DataGridViewRadioButtonColumn Inherits DataGridViewColumn '''ラジオボタンが属するグループ名 Private _groupName As String ''' ''' ''' Public Sub New() MyBase.New(New DataGridViewRadioButtonCell) End Sub ''' ''' ''' ''' Public Overrides Function Clone() As Object Dim col As DataGridViewRadioButtonColumn = _ DirectCast(MyBase.Clone(), DataGridViewRadioButtonColumn) ' プロパティを追加したとき、この場所に追記する ' Cloneメソッドに記述しない場合、プロパティブラウザで表示・編集は ' されるが、保存されないプロパティとなる col.GroupName = Me.GroupName Return col End Function ''' ''' ''' ''' ''' Public Overrides Property CellTemplate() As DataGridViewCell Get Return MyBase.CellTemplate End Get Set(ByVal value As DataGridViewCell) If Not (value Is Nothing) AndAlso _ Not value.GetType().IsAssignableFrom(GetType(DataGridViewRadioButtonCell)) Then Throw New InvalidCastException("Must be a DataGridViewRadioButtonCell") End If MyBase.CellTemplate = value End Set End Property ''' ''' ラジオボタンが属するグループ名 ''' ''' ''' ''' ''' ここで設定されたグループ名により、同一行内・同一グループのチェック ''' 状態のラジオボタンがひとつになるよう制御される Public Property GroupName As String Get Return _groupName End Get Set(value As String) _groupName = value End Set End Property End Class ''' ''' ラジオボタンのセルクラス ''' ''' Public Class DataGridViewRadioButtonCell Inherits DataGridViewCell '''ラジオボタンの描画サイズ Private Const RADIO_SIZE As Integer = 16 ''' ''' ''' ''' Public Sub New() MyBase.New() End Sub ''' ''' 1 ''' ''' ''' Public Overrides Function Clone() As Object Dim cell = DirectCast(MyBase.Clone(), DataGridViewRadioButtonCell) Return cell End Function ''' ''' ''' ''' ''' ''' ''' ''' ''' ''' ''' Protected Overrides Function GetFormattedValue(value As Object, rowIndex As Integer, ByRef cellStyle As DataGridViewCellStyle, valueTypeConverter As TypeConverter, formattedValueTypeConverter As TypeConverter, context As DataGridViewDataErrorContexts) As Object Return _val(value) End Function ''' ''' ''' ''' ''' ''' Private Shared Function _val(v As Object) As Boolean Try Return If(IsDBNull(v) OrElse IsNothing(v), False, Convert.ToBoolean(v)) Catch ex As Exception Return False End Try End Function ''' ''' ''' ''' ''' ''' ''' ''' ''' ''' ''' ''' ''' ''' ''' Protected Overrides Sub Paint(graphics As System.Drawing.Graphics, _ clipBounds As System.Drawing.Rectangle, _ cellBounds As System.Drawing.Rectangle, _ rowIndex As Integer, _ elementState As System.Windows.Forms.DataGridViewElementStates, _ value As Object, _ formattedValue As Object, _ errorText As String, _ cellStyle As System.Windows.Forms.DataGridViewCellStyle, _ advancedBorderStyle As System.Windows.Forms.DataGridViewAdvancedBorderStyle, _ paintParts As System.Windows.Forms.DataGridViewPaintParts) MyBase.Paint(graphics, clipBounds, cellBounds, rowIndex, elementState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts) ' 背景色の描画 If (paintParts And DataGridViewPaintParts.Background) = DataGridViewPaintParts.Background Then Dim brush As New SolidBrush(If(elementState And DataGridViewElementStates.Selected, _ cellStyle.SelectionBackColor, cellStyle.BackColor)) graphics.FillRectangle(brush, cellBounds) brush.Dispose() End If ' 境界線の描画 If (paintParts And DataGridViewPaintParts.Border) = DataGridViewPaintParts.Border Then PaintBorder(graphics, clipBounds, cellBounds, cellStyle, advancedBorderStyle) End If ' セルの幅、高さがラジオボタンの描画サイズより小さい場合は、描画処理を飛ばす If cellBounds.Width < RADIO_SIZE OrElse cellBounds.Height < RADIO_SIZE Then Return End If ' ラジオボタンをセルの真ん中に描画(描画サイズは固定) Dim rect As Rectangle = New Rectangle(New Point(cellBounds.Left + (cellBounds.Width - RADIO_SIZE) / 2, _ cellBounds.Top + (cellBounds.Height - RADIO_SIZE) / 2), _ New Size(RADIO_SIZE, RADIO_SIZE)) Dim v = _val(value) ControlPaint.DrawRadioButton(graphics, rect, If(v, ButtonState.Checked, ButtonState.Inactive)) End Sub ''' ''' ''' ''' ''' ''' Protected Overrides Sub OnKeyPress(e As System.Windows.Forms.KeyPressEventArgs, rowIndex As Integer) MyBase.OnKeyPress(e, rowIndex) If [ReadOnly] Then Return End If ' スペースキーが押されたとき、ラジオボタンのチェック状態の更新 If e.KeyChar = Microsoft.VisualBasic.ChrW(Keys.Space) Then updateValues(DataGridView.CurrentCell.ColumnIndex, rowIndex) End If End Sub ''' ''' ''' ''' ''' Protected Overrides Sub OnClick(e As System.Windows.Forms.DataGridViewCellEventArgs) MyBase.OnClick(e) If [ReadOnly] Then Return End If ' ラジオボタンのチェック状態の更新 updateValues(e.ColumnIndex, e.RowIndex) End Sub ''' ''' ラジオボタンのチェック状態を更新 ''' ''' ''' ''' Private Sub updateValues(columnIndex As Integer, rowIndex As Integer) Dim currentColumn As DataGridViewRadioButtonColumn = _ TryCast(Me.DataGridView.Columns(columnIndex), DataGridViewRadioButtonColumn) For Each column As DataGridViewColumn In Me.DataGridView.Columns ' ラジオボタンセル以外は処理を飛ばす If Not (TypeOf (column) Is DataGridViewRadioButtonColumn) Then Continue For End If ' カレントセルと異なるグループ名は処理を飛ばす Dim radioColumn As DataGridViewRadioButtonColumn = TryCast(column, DataGridViewRadioButtonColumn) If radioColumn.GroupName <> currentColumn.GroupName Then Continue For End If Dim dgvc = Me.DataGridView.Rows(rowIndex).Cells(column.Index) ' 更新後のチェック状態を求める Dim v = If(radioColumn.Index = currentColumn.Index, True, False) ' 値の更新が生じない場合は処理を飛ばす Dim prev = _val(dgvc.Value) If prev = v Then Continue For End If dgvc.Value = v ' イベントを発生させる ' ※チェック状態を更新した回数分イベントが発生する Dim newEa = New DataGridViewCellEventArgs(columnIndex, rowIndex) RaiseCellValueChanged(newEa) Me.DataGridView.InvalidateCell(dgvc) Me.DataGridView.NotifyCurrentCellDirty(True) Next End Sub ''' ''' ''' ''' ''' ''' Public Overrides ReadOnly Property DefaultNewRowValue As Object Get Return False End Get End Property ''' ''' ''' ''' ''' ''' Public Overrides Property ValueType As System.Type Get Return GetType(Boolean) End Get Set(value As System.Type) Throw New InvalidOperationException End Set End Property ''' ''' ''' ''' ''' ''' Public Overrides ReadOnly Property FormattedValueType As Type Get Return GetType(Boolean) End Get End Property End Class
ソースのダウンロード: DataGridViewRadioButtonColumn.zip
大変参考になります。
この処理を使用して、アプリを作成してみましたが、この処理を利用してラジオボタンを選択状態から開始することはできるでしょか?
とても参考になります、ありがとうございます。
行ではなく、列の選択をするにはどのように変更をすればできるでしょうか?
VBを始めたばかりです。よろしくお願いします。