4

I'm trying to create a DataGridView column hosted with Radiobuttons. I've been following this MSDN article.

Although I have changed the code from the tutorial to write my own classes, it doesn't work as expected. The thing is I'm not entirely sure what I'm missing. It gives no errors when compiling. But it appears as Checkboxes instead of Radiobuttons. enter image description here

I have attached the Visual Studio project here. And for those who are unsure about downloading unknown attachments, here are the 3 classes I have written.

RadiobuttonColumn class. It inherits the DataGridViewColumn class.

using System;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    class RadiobuttonColumn : DataGridViewColumn
    {
        public RadiobuttonColumn()
            : base(new RadiobuttonCell())
        {
        }

        public override DataGridViewCell CellTemplate
        {
            get
            {
                return base.CellTemplate;
            }
            set
            {
                if (value != null && !value.GetType().IsAssignableFrom(typeof(RadiobuttonCell)))
                {
                    throw new InvalidCastException("Must be a RadiobuttonCell");
                }
            }
        }
    }
}

UPDATED RadiobuttonCell class inherits DataGridViewCell class.


using System;
using System.Windows.Forms;
using System.Drawing;

namespace DataGridView_Radiobutton_column
{
    public class RadiobuttonCell : DataGridViewCell
    {
        public RadiobuttonCell()
            : base()
        { 
        }

        public override void InitializeEditingControl(int rowIndex, object initialFormattedValue, DataGridViewCellStyle dataGridViewCellStyle)
        {
            base.InitializeEditingControl(rowIndex, initialFormattedValue, dataGridViewCellStyle);
            RadiobuttonEditingControl rdb = DataGridView.EditingControl as RadiobuttonEditingControl;
            if (this.Value == null)
            {
                rdb.Checked = false;
            }
            else
            {
                rdb.Checked = (Boolean)this.Value;
            }
        }

        public override Type EditType
        {
            get
            {
                return typeof(RadiobuttonEditingControl);
            }
        }

        public override Type ValueType
        {
            get
            {
                return typeof(Boolean);
            }
        }

        public override object DefaultNewRowValue
        {
            get
            {
                return false;
            }
        }

        protected override void Paint(System.Drawing.Graphics graphics, System.Drawing.Rectangle clipBounds, System.Drawing.Rectangle cellBounds, int rowIndex, DataGridViewElementStates cellState, object value, object formattedValue, string errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts)
        {
            base.Paint(graphics, clipBounds, cellBounds, rowIndex, cellState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts);

            
            Rectangle rectRadioButton = default(Rectangle);

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

            ControlPaint.DrawRadioButton(graphics, rectRadioButton, ButtonState.Normal);
        }
    }
}

The RadiobuttonEditingControl class inherits the RadioButton class and implements IDataGridViewEditingControl Interface's methods.

using System;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    class RadiobuttonEditingControl : RadioButton, IDataGridViewEditingControl
    {
        DataGridView dataGridView;
        private bool valueChanged = false;
        int rowIndex;

        public RadiobuttonEditingControl()
        {
            this.Checked = false;
        }

        public object EditingControlFormattedValue
        {
            get
            {
                return this.Checked = true;
            }
            set
            {
                this.Checked = false;
            }
        }

        public object GetEditingControlFormattedValue(DataGridViewDataErrorContexts context)
        {
            return EditingControlFormattedValue;
        }

        public void ApplyCellStyleToEditingControl(DataGridViewCellStyle dataGridViewCellStyle)
        {
        }

        public int EditingControlRowIndex
        {
            get
            {
                return rowIndex;
            }
            set
            {
                rowIndex = value;
            }
        }

        public bool EditingControlWantsInputKey(Keys key, bool dataGridViewWantsInputKey)
        {
            switch (key & Keys.KeyCode)
            {
                case Keys.Space:
                    return true;
                default:
                    return !dataGridViewWantsInputKey;
            }
        }

        public void PrepareEditingControlForEdit(bool selectAll)
        {
        }

        public bool RepositionEditingControlOnValueChange
        {
            get
            {
                return false;
            }
        }

        public DataGridView EditingControlDataGridView
        {
            get
            {
                return dataGridView;
            }
            set
            {
                dataGridView = value;
            }
        }

        public bool EditingControlValueChanged
        {
            get
            {
                return valueChanged;
            }
            set
            {
                valueChanged = value;
            }
        }

        public Cursor EditingPanelCursor
        {
            get
            {
                return base.Cursor;
            }
        }

        protected override void OnCheckedChanged(EventArgs eventArgs)
        {
            valueChanged = true;
            this.EditingControlDataGridView.NotifyCurrentCellDirty(true);
            base.Checked = false;
        }
    }
}

If anyone could take a look at this and point me to the right direction as to what changes should be done in the code, I'd be grateful.

Thank you.

Community
  • 1
  • 1
Isuru
  • 30,617
  • 60
  • 187
  • 303

1 Answers1

2

What happens when you begin editing a cell? It turns into a radio button.

This is because you derived from a checkbox cell which paints itself as a checkbox.

The DGV is not a grid of controls. It's a grid of boxes that are painted to look like controls until the user attempts to edit a cell. At that point the DGV moves the cell's (one and only) editing control into position and makes it visible for the user to interact with.

You're going to have to derive from the base DataGridViewCell class and implement all of the painting code too.

The example code doesn't have to do this because a textbox cell knows how to paint text.

Updated

The ControlPaint class can help you out.

Tergiver
  • 14,171
  • 3
  • 41
  • 68
  • Thank you Tergiver for the response. I have changed the `RadiobuttonCell` class as you've instructed. Please see the updated code in my original post. I've inherited the `DataGridViewCell` class and did override the `Paint` method. However I'm facing a small problem. The background of the DataGridView appears transparent. [Here](http://i.imgur.com/63Df7.png) is a screenshot. How can I overcome this issue? – Isuru Jul 28 '12 at 09:40
  • @nK0de You have to paint the background as well. Use the cell's style to determine if the cell is selected or not. I think you can just use `graphics.Clear(cellStyle.BackColor : cellStyle.SelectedColor)`. You also want to paint the radio button based on the cell's current value. – Tergiver Jul 29 '12 at 01:16
  • @nK0de Also, drawing happens in phases so you want to use the paintParts parameter to determine which part you are supposed to paint. – Tergiver Jul 29 '12 at 01:18
  • 1
    @nK0de I had a look at the source code (from ILSpy) of `DataGridViewCheckBoxCell`. You should look at it yourself. First thing to note is that they do not use an in-place editing control (return null for EditType), they handle both painting and interaction. The painting is fairly complex because they handle visual styles correctly, but the code shows you how to paint every part (border, background, focus, foreground, and error icon). – Tergiver Jul 30 '12 at 16:57
  • You're right about `EditType`. I came across [this](http://msdn.microsoft.com/en-US/library/aa730882(v=vs.80)) article and it is mentioned there also. I think I can get it done now. But yes, Painting is a bit complex. I think I should look up a couple of tutorials on GDI+ rather than just copy-pasting the code. Thank you very much for taking time for my question. I really appreciate it. :) – Isuru Jul 31 '12 at 14:34
  • 1
    @nK0de There really isn't much in the way of GDI there since they use the base class code for most bits and a VisualRenderer or ControlPaint depending on whether visual styles are enabled or not for the rest of the painting. ControlPaint is simple, the VisualRenderer is a bit of a monster. I don't think you should copy and paste, but go through that code and use MSDN to learn about the specific bits you may not understand, or ask questions here. – Tergiver Jul 31 '12 at 16:21