更改Datagridview复选框单元格的复选框大小并增加可点击区域

问题描述 投票:0回答:2

我的 .net core Winform 数据 GridVew 中有一个复选框列。
我已经将复选框放大以便用户更容易单击。

我的代码在里面

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;

这些是我的参考链接,
如何更改 DatagridviewCheckboxCell 中的复选框大小
增加C#中#DataGridView中复选框的大小

结果如下,

但问题是点击区域,即使复选框的尺寸更大,我意识到可点击区域仍然是原来的尺寸。
如下图所示,绿色区域是可点击区域,

我想让可点击区域与复选框的大小一样大,如下所示,

有什么解决办法吗?

c# winforms checkbox datagridview datagridviewcheckboxcell
2个回答
2
投票

当您用鼠标单击

DataGridViewCheckBoxCell
来切换 Checked 状态时,您必须单击单元格内的 content,单击单元格内的其他位置不会改变任何内容。
DataGridViewCheckBoxCell
的内容就是那个小盒子区域。因此,仅绘制一个更大的框不会调整
content
区域的大小或重新定位(根据列的 DefaultCellStyle.Alignment),并且它保持不变。您需要编写代码来告知,内容区域已被单击,并且应调用相关的基本方法和事件。

我会创建自定义

DataGridViewCheckBox
列和单元格来应用此要求。

在项目的命名空间中,从

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;
    }
}

还有一个源自

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 OnMouseUp(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);
        }
    }
}

在网格设计器中重建并检查新的列类型。

如果您有数据绑定网格,请将

AutoGenerateColumns
属性设置为
false
并手动添加列。例如:

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;


0
投票

博士。 Null 的回答确实对我的工作有帮助,但我在使用 CellContentClick 时遇到了一个小问题,如果您在侧面单击自定义复选框,它不会注册自定义复选框的单击;如果复选框比原来的大。该问题可能是因为 CellContentClick 事件考虑的是原始复选框或其大小。该复选框及其值将起作用,但问题仅依赖于我想在单击复选框时进行回调

我当前使用的唯一解决方案是创建一个继承图像列并使其像复选框一样的自定义类,而不是创建复选框列

这是应用它的分步过程:

  1. 从program.cs或任何cs文件创建代码,这是代码
 public class customImageColumn : DataGridViewColumn
 {
     public customImageColumn() : base()
     {
         CellTemplate = new customImageColumnCell();
     }
 }

public class customImageColumnCell : DataGridViewImageCell
{
    private bool state = false;
    public Image checkedImage, uncheckedImage;

    public object TrueValue;
    public object FalseValue;

    public bool BoolValue { get => state; }
    public object formattedValue { get => state ? TrueValue : FalseValue; }

    public customImageColumnCell() : base()
    {
        ImageLayout = DataGridViewImageCellLayout.Zoom;
        checkedImage = /*your checked image here*/;
        uncheckedImage = /*your checked image here*/;;
        Value = uncheckedImage;
    }

    public void changeState()
    {
        state = !state;
        Value = state ? checkedImage : uncheckedImage;
    }
}

请注意,您可以在properties.resources上获取和设置图像

  1. 将其应用到图像栏
 customImageColumn imageColumn= new customImageColumn();
 yourDataGridView.Columns.Add(imageColumn);

enter image description here

您也可以手动创建它,只需将列类型设置为customImageColumn,最好将customImageColumn存储在该上下文中的program.cs文件中。

  1. 设置CellContentClick
private void yourDataGridView_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
    if (e.ColumnIndex == /*the index of the custom checkbox column*/ && e.ColumnIndex > 0)
    {
        customImageColumnCell c = (customImageColumnCell)mainDataView.Rows[e.RowIndex].Cells[e.ColumnIndex];
        c.changeState();
        //for all checkbox to work

        /*you can place your callback here
          get the bool value like this c.boolvalue
          or the formatted value like this c.formattedValue*/
    }
}

请注意,您可以使用 Dr. Null 的方法,因为我的方法更加非正统,这只是为了满足我在单击复选框列时进行回调的要求

© www.soinside.com 2019 - 2024. All rights reserved.