Search

Custom Search

Thursday, September 4, 2008

Using DataGridView CheckBox Column as RadioButton (OptionButton)

Level: Beginner

Knowledge Required:

  • DataGridView Control
  • Data Binding
Description:
In this post we shall see that how we can transform DataGridView control’s CheckBox column into Radio Button (option button).

I have done 2 main things,
  1. Created a back-end logic when user clicks on CheckBox Column so only one CheckBox should be checked at a time
  2. Change the look of CheckBox column so it looks a Radio Button Column
So to understand the first one, consider a DataGridView control as shown in the above figure. This DataGridView control is actually bind with a DataSet for example,

As you can see there are 2 columns. The IsSelected column is actually a Boolean column which is normally rendered as CheckBox in DataGridView control. What we will be doing is that we first set our DataGridView to Read Only i.e.,

AllowUserToAddRows = False
AllowUserToDeleteRows = False
ReadOnly = True

We are making our DataGridView control Read Only because it is easier to set the CheckBox checked or unchecked programmatically otherwise DataGridView control itself will be interfering and will create problems and complexities for us.

OK now whenever user clicks on CheckBox we will be performing our custom operation. To do this we will use the DataGridView’s CellContentClick event. Here is the code,

Private Sub ShutDownOptionsDataGridView_CellContentClick(ByVal sender As System.Object, ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) Handles ShutDownOptionsDataGridView.CellContentClick
    If e.ColumnIndex = Me.columnIsSelected.Index Then
        Dim drv As DataRowView
        Dim rowShutDownOption As ShutdownOptionDataSet.ShutDownOptionsRow
        ' in this event handler we know that which DataGridView's row is clicked
        ' so we are going to extract out the actual DataTable's row which is
        ' bind with this DataGridView's Row
        drv = CType(Me.ShutDownOptionsDataGridView.Rows(e.RowIndex).DataBoundItem, DataRowView)
        ' get the DataTable's row
        rowShutDownOption = CType(drv.Row, ShutdownOptionDataSet.ShutDownOptionsRow)

        ' get the row which is currently selected
        Dim rowCurrentlySelected() As ShutdownOptionDataSet.ShutDownOptionsRow
        rowCurrentlySelected = Me.ShutdownOptionDataSet.ShutDownOptions.Select("IsSelected=True")
        ' if some row found then make it de-selected
        If rowCurrentlySelected.Length > 0 Then
            rowCurrentlySelected(0).IsSelected = False
        End If
            ' ok now select the row which is clicked
        rowShutDownOption.IsSelected = True
    End If
End Sub


What we do is first get the row in which IsSelected=True and we make that row IsSelected=False. Then we set the row which is clicked as IsSelected=True.

Next thing is to change the look of CheckBox to OptionButton / RadioButton. For this purpose we will be using DataGridView’s CellPainting event. Here is the code,

Private Sub ShutDownOptionsDataGridView_CellPainting(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellPaintingEventArgs) Handles ShutDownOptionsDataGridView.CellPainting
    If e.ColumnIndex = Me.columnIsSelected.Index AndAlso _
        e.RowIndex >= 0 Then
        e.PaintBackground(e.ClipBounds, True)

        Dim rectRadioButton As Rectangle

        rectRadioButton.Width = 14
        rectRadioButton.Height = 14
        rectRadioButton.X = e.CellBounds.X + (e.CellBounds.Width - rectRadioButton.Width) / 2
        rectRadioButton.Y = e.CellBounds.Y + (e.CellBounds.Height - rectRadioButton.Height) / 2

        If IsDBNull(e.Value) OrElse e.Value = False Then
            ControlPaint.DrawRadioButton(e.Graphics, rectRadioButton, ButtonState.Normal)
        Else
            ControlPaint.DrawRadioButton(e.Graphics, rectRadioButton, ButtonState.Checked)
        End If

        e.Paint(e.ClipBounds, DataGridViewPaintParts.Focus)

        e.Handled = True
    End If
End Sub

As you can see we have used the ControlPaint class to draw the RadioButton / OptionButton.

Download:
DGVCheckBoxAsRadioButton.zip

10 comments:

Patrick said...

great post thanks, here is the C# translation of the Painting events. Note, the column I needed this for was titled "Primary":

private void gvDocumentList_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
{
if (e.ColumnIndex == gvDocumentList.Columns["Primary"].Index && e.RowIndex >= 0)
{
e.PaintBackground(e.ClipBounds, true);

Rectangle rectRadioButton = new Rectangle();

rectRadioButton.Width = 14;
rectRadioButton.Height = 14;
rectRadioButton.X = e.CellBounds.X + (e.CellBounds.Width - rectRadioButton.Width) / 2;
rectRadioButton.Y = e.CellBounds.Y + (e.CellBounds.Height - rectRadioButton.Height) / 2;

if (e.Value == DBNull.Value || (bool)e.Value == false)
{
ControlPaint.DrawRadioButton(e.Graphics, rectRadioButton, ButtonState.Normal);
}
else
{
ControlPaint.DrawRadioButton(e.Graphics, rectRadioButton, ButtonState.Checked);
}

e.Paint(e.ClipBounds, DataGridViewPaintParts.Focus);

e.Handled = true;
}
}

J said...

Hi,
Thank you very much. This code has helped me a lot and Saved lot of time. Thank you very much.

Ole Nissen said...

Hi,
Thanks for this code. It helped me a lot.

Unfortunatly i am not good enough in VB, because i have some trouble with my project.
I want to have a datagrid with three columns of RadioButtons an one Column with a List of filenames.. If i click on one RadioButton, i want the other RadioButtons in this particular row to be deselected...

Can anybody provide some help???

Thanks
Ole

Arsalan Tamiz said...

Hi Ole,

The thing which you required is alot simpler. Do the followings

1) Create a DataTable with 4 Fields. 3 Boolean and 1 for File Name
2) Bind this DataTable with DataGridView
3) Make the first 3 Columns Read-only
4) In the CellContentClick Event Handler, use this logic:
if Clicked Column = any of first 3 column Then
Get the DataTable Row
Make all the other boolean columns = False
And then Set the clicked column = True
End If

TD said...

Thanks! This was exactly what I needed.

TD said...

Arsalan, Thanks again for the post. This works pretty well, but I actually do need the user to have the ability to add and update rows. Can you elaborate on the additional problems and complexities that you mention? When the grid is not Read-Only the procedure’s behavior is really flaky.

TD

Arsalan Tamiz said...

@TD,

Atleast "option button" column should be readonly.

flacoman said...

Great post!!!

Tip:

If you want Windows XP styles in the radio buttons you can use this code in the cellpaint event:

If e.ColumnIndex = 1 AndAlso e.RowIndex >= 0 Then
e.PaintBackground(e.ClipBounds, True)

Dim p As Point
p.X = e.CellBounds.X + (e.CellBounds.Width - 14) / 2
p.Y = e.CellBounds.Y + (e.CellBounds.Height - 14) / 2


If IsDBNull(e.Value) OrElse e.Value = False Then
RadioButtonRenderer.DrawRadioButton(e.Graphics, p, VisualStyles.RadioButtonState.UncheckedNormal)
Else
RadioButtonRenderer.DrawRadioButton(e.Graphics, p, VisualStyles.RadioButtonState.CheckedNormal)
End If

e.Paint(e.ClipBounds, DataGridViewPaintParts.Focus)

e.Handled = True
End If

Greets

Arsalan Tamiz said...

Thanks flacoman for the input.

Barman said...

Thank you! I was looking for it quite long, but this looks so nice and easy!