winforms 更改数据网格视图复选框单元格的复选框大小并增加可单击区域

0s7z1bwu  于 2022-11-17  发布在  其他
关注(0)|答案(1)|浏览(280)

我在我的.net核心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;

这些是我的参考链接,
How to change checkBox Size in DatagridviewCheckboxCell
Increase the size of Checkbox in #DataGridView in C#
结果如下所示:

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

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

有没有解决的办法?

e7arh2l6

e7arh2l61#

当你用鼠标点击一个DataGridViewCheckBoxCell来切换 Checked 状态时,你必须点击单元格内的content,点击单元格内的其他地方并不会改变什么。DataGridViewCheckBoxCell的内容就是那个小方框区域。所以,仅绘制较大的框不会调整大小或重新定位(根据列的DefaultCellStyle.Alignment)那个 content 区域和它保持不变。你需要编写代码来告诉,内容区域已经被点击,相关的基方法和事件应该被调用。
我将创建自定义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);
        }
    }
}

在网格的设计器中重新生成并 checkout 新的列类型。

如果您有数据系结网格,请将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;

相关问题