Home > Back-end >  Change checkBox Size of Datagridview Checkbox Cell and increase the clickable area
Change checkBox Size of Datagridview Checkbox Cell and increase the clickable area

Time:09-01

I have a checkbox column in my .net core Winform data GridVew.
I already made the checkbox bigger to be easier for the user to click.

My code inside CellPainting,

                e.PaintBackground(e.CellBounds, true);
                ControlPaint.DrawCheckBox(e.Graphics, e.CellBounds.X   1, e.CellBounds.Y   5,
                    e.CellBounds.Width - 10, e.CellBounds.Height - 10,
                    (bool)e.FormattedValue ? ButtonState.Checked : ButtonState.Normal);
                e.Handled = true;

Those are my reference links,
enter image description here

But the problem is the click area, even though the size of the checkbox is bigger, I realize the clickable area is still in its original size.
As I show below, the green area is clickable area,
enter image description here

I want to make the clickable area as big as the checkbox's size as show below,
enter image description here

Is there any solution?

CodePudding user response:

When you mouse-click a DataGridViewCheckBoxCell to toggle the Checked state, you have to click on the content within the cell, clicking on elsewhere within the cell does not change a thing. The content of a DataGridViewCheckBoxCell is that small box area. So, just drawing a bigger box does not resize or reposition (according to the column's DefaultCellStyle.Alignment) that content area and it remains the same. You need to code for that to tell, the content area has been clicked and the relevant base methods and events should be invoked.

I'd create custom DataGridViewCheckBox column and cell to apply this requirement.

Within your project's namespace, derive a new class from DataGridViewCheckBoxColumn:

public class CustomDataGridViewCheckBoxColumn : DataGridViewCheckBoxColumn
{
    public CustomDataGridViewCheckBoxColumn() : base() =>
        CellTemplate = new CustomDataGridViewCheckBoxCell();

    public override DataGridViewCell CellTemplate
    {
        get => base.CellTemplate;
        set
        {
            if (value != null &&
                !value.GetType().IsAssignableFrom(typeof(CustomDataGridViewCheckBoxCell)))
                throw new InvalidCastException("CustomDataGridViewCheckBoxCell.");

            base.CellTemplate = value;
        }
    }

    [Category("Appearance")]
    [DefaultValue(typeof(Size), "17, 17")]
    [Description("The size of the check box.")]
    public Size CheckBoxSize { get; set; } = new Size(17, 17);

    // We should copy the new properties.
    public override object Clone()
    {
        var c = base.Clone() as CustomDataGridViewCheckBoxColumn;
        c.CheckBoxSize = CheckBoxSize;
        return c;
    }
}

And another one derived from DataGridViewCheckBoxCell:

public class CustomDataGridViewCheckBoxCell : DataGridViewCheckBoxCell
{
    private Rectangle curCellBounds;
    private Rectangle checkBoxRect;

    public CustomDataGridViewCheckBoxCell() : base() { }

    protected override void Paint(
        Graphics g,
        Rectangle clipBounds,
        Rectangle cellBounds,
        int rowIndex,
        DataGridViewElementStates elementState,
        object value,
        object formattedValue,
        string errorText,
        DataGridViewCellStyle cellStyle,
        DataGridViewAdvancedBorderStyle advancedBorderStyle,
        DataGridViewPaintParts paintParts)
    {
        // Paint default except the check box parts.
        var parts = paintParts & ~(DataGridViewPaintParts.ContentForeground 
            | DataGridViewPaintParts.ContentBackground);

        base.Paint(g, 
            clipBounds, 
            cellBounds, 
            rowIndex, 
            elementState, 
            value, 
            formattedValue, 
            errorText, 
            cellStyle, 
            advancedBorderStyle, 
            parts);
            
        if (curCellBounds != cellBounds)
        {
            // To get the box size...
            var col = OwningColumn as CustomDataGridViewCheckBoxColumn;

            curCellBounds = cellBounds;
            // ToDo: Use col.DefaultCellStyle.Alignment or
            // DataGridView.ColumnHeadersDefaultCellStyle.Alignment
            // to position the box. MiddleCenter here...
            checkBoxRect = new Rectangle(
                (cellBounds.Width - col.CheckBoxSize.Width) / 2   cellBounds.X,
                (cellBounds.Height - col.CheckBoxSize.Height) / 2   cellBounds.Y,
                col.CheckBoxSize.Width,
                col.CheckBoxSize.Height);
        }

        ControlPaint.DrawCheckBox(g, checkBoxRect, (bool)formattedValue 
            ? ButtonState.Checked | ButtonState.Flat 
            : ButtonState.Flat);
    }

    // In case you don't use the `Alignment` property to position the 
    // box. This is to disallow toggling the state if you click on the
    // original content area outside the drawn box.
    protected override void OnContentClick(DataGridViewCellEventArgs e)
    {
        if (!ReadOnly &&
            checkBoxRect.Contains(DataGridView.PointToClient(Cursor.Position)))
            base.OnContentClick(e);
    }

    protected override void OnContentDoubleClick(DataGridViewCellEventArgs e)
    {
        if (!ReadOnly &&
            checkBoxRect.Contains(DataGridView.PointToClient(Cursor.Position)))
            base.OnContentDoubleClick(e);
    }

    // Toggle the checked state by mouse clicks...
    protected override void onm ouseUp(DataGridViewCellMouseEventArgs e)
    {
        base.OnMouseUp(e);

        if (!ReadOnly && e.Button == MouseButtons.Left &&
            checkBoxRect.Contains(DataGridView.PointToClient(Cursor.Position)))
        {
            Value = Value == null || !Convert.ToBoolean(Value);
            DataGridView.RefreshEdit();
            DataGridView.NotifyCurrentCellDirty(true);
        }    
    }

    // ... and Space key...
    protected override void OnKeyDown(KeyEventArgs e, int rowIndex)
    {
        base.OnKeyDown(e, rowIndex);
        if (!ReadOnly && e.KeyCode == Keys.Space)
        {
            Value = Value == null || !Convert.ToBoolean(Value.ToString());
            DataGridView.RefreshEdit();
            DataGridView.NotifyCurrentCellDirty(true);
        }
    }
}

Rebuild and check out the new column type in the grid's designer.

SO73550925A

In case you have a data-bound grid, set the AutoGenerateColumns property to false and add the columns manually. For example:

private readonly static Random rnd = new Random();
//..

var dt = new DataTable();
dt.Columns.AddRange(new[]
{
    new DataColumn("Default", typeof(bool)),
    new DataColumn("Custom", typeof(bool))
});

for (int i = 1; i < 6; i  )
    dt.Rows.Add(rnd.Next(0, 2), rnd.Next(0, 2));

dataGridView1.AutoGenerateColumns = false;
dataGridView1.Columns.AddRange(new[]
{
    new DataGridViewCheckBoxColumn { HeaderText = "Default" },
    new CustomDataGridViewCheckBoxColumn 
    { 
        HeaderText = "Custom",
        CheckBoxSize = new Size(32, 32) 
    }
});
dataGridView1.DataSource = dt;

SO73550925B

  • Related