Winform重绘DataGridView选择框

前言:其实我感觉在Winform中的话,DataGridView提供的属性已经足够我们使用了,包括简单调一些背景、字体以及其他样式也能做到简单大方。但是在选择框这里确实是个短板,首先是调整行的大小或者字体颜色的时候,CheckBox并不会随着改变,单独设置也没啥效果;简而言之,无论列高设置多少,这个控件依然是那么一点。如果使用到触摸屏上的话,操作就会很难受,美观度的话更是差强人意。.

所以,这里单独对CheckBox进行一个重绘,其实主要还是用来改变大小以及实现全选功能。

  1. 新建一个自定义控件继承自DataGridView,并在其中定义以下属性

 public partial class GridViewEx : DataGridView    {        [Description("选择框选中样式")]        public Font CheckFont { get; set; } = new Font("黑体", 18);        [Description("选择框选中颜色")]        public Color CheckColor { get; set; } = Color.FromArgb(0, 0, 139);        [Description("选择框未选中颜色")]        public Color NormalCheckColor { get; set; } = Color.Black;
        private string _CheckAllColumn;        [Description("使用全选按钮的列")]        public string UseCheckAllColumn        {            get { return _CheckAllColumn; }            set { _CheckAllColumn = value; }        }
  1. 绘制每一列的选择框样式,其实选择框可以考虑使用图片以提升美观度,但是基于效率考虑的话,我是选择了绘制矩形,然后在矩形内部绘制一个对勾进行选中

     private void DrawCheckBox(Graphics graphics, Rectangle rect, bool isCheck)        {            graphics.DrawRectangle(new Pen(NormalCheckColor), rect);            if (isCheck)            {                SizeF textSize = graphics.MeasureString("√", CheckFont);                graphics.DrawString("√", CheckFont, new SolidBrush(CheckColor), rect.X + (rect.Height - textSize.Width) / 2, rect.Y + (rect.Height - textSize.Height) / 2);            }        }
  1. 绘制头部的选择框样式,用来实现全选功能

     private void DrawHeaderCheckBox(Graphics graphics, Rectangle rect, bool isCheck)        {                        graphics.DrawRectangle(new Pen(ColumnHeadersDefaultCellStyle.ForeColor), rect);            if (isCheck)            {                SizeF textSize = graphics.MeasureString("√", CheckFont);                graphics.DrawString("√", CheckFont, new SolidBrush(ColumnHeadersDefaultCellStyle.ForeColor), rect.X + (rect.Height - textSize.Width) / 2, rect.Y + (rect.Height - textSize.Height) / 2);            }        }
  1. OnCellPainting事件中进行绘制调用,这里的大小是取了行高的一半。所以选择框的大小是根据行高自动调整的。值得注意的是,这里加入了一个UseCheckAllColumn字段,只有当设置了这个字段需要有全选时才会绘制全选选择框,可以适应有多列选择框的情况。

     protected override void OnCellPainting(DataGridViewCellPaintingEventArgs e)        {            base.OnCellPainting(e);
                int size = e.CellBounds.Height / 2;            int x = e.CellBounds.X + (e.CellBounds.Width - size) / 2;            int y = e.CellBounds.Y + (e.CellBounds.Height - size) / 2;            Rectangle rect = new Rectangle(x, y, size, size);
                if (e.RowIndex == -1 && e.ColumnIndex > -1 && UseCheckAllColumn != null && Columns[e.ColumnIndex] is DataGridViewCheckBoxColumn)            {                var column = Columns[e.ColumnIndex];                if (column.Tag == null)                {                    column.Tag = false;                }                column.HeaderText = "";                e.PaintBackground(rect, true);                DrawHeaderCheckBox(e.Graphics, rect, (bool)column.Tag);                e.Handled = true;            }            else if (e.RowIndex > -1 && e.ColumnIndex > -1 && Columns[e.ColumnIndex] is DataGridViewCheckBoxColumn)            {                e.PaintBackground(rect, true);                DrawCheckBox(e.Graphics, rect, (bool)e.Value);                e.Handled = true;            }        }
  1. 在选中或者取消选中的时候需要重绘对应的状态,所以在OnCellClick事件中重新绘制一遍,同时如果点击的是全选时,则需要对所有行进行一个状态重绘。

     protected override void OnCellClick(DataGridViewCellEventArgs e)        {            base.OnCellClick(e);            if (e.RowIndex == -1 && e.ColumnIndex > -1 && Columns[e.ColumnIndex].Name == UseCheckAllColumn)            {                DataGridViewColumn column = Columns[e.ColumnIndex];                if (column is DataGridViewCheckBoxColumn)                {                    column.Tag = !(bool)column.Tag;                    foreach (DataGridViewRow row in Rows)                    {                        row.Cells[e.ColumnIndex].Value = column.Tag;                    }                    InvalidateCell(e.ColumnIndex, e.RowIndex);                }            }            else if (e.RowIndex > -1 && e.ColumnIndex > -1)            {                DataGridViewColumn column = Columns[e.ColumnIndex];                if (column is DataGridViewCheckBoxColumn)                {                    bool value = (bool)Rows[e.RowIndex].Cells[e.ColumnIndex].Value;                    Rows[e.RowIndex].Cells[e.ColumnIndex].Value = !value;                    InvalidateCell(e.ColumnIndex, e.RowIndex);                }            }        }
  1. 最后,我们需要在数据源发生改变的时候,对选中状态进行一个初始化,也就是回到未选中状态

     protected override void OnDataBindingComplete(DataGridViewBindingCompleteEventArgs e)        {            base.OnDataBindingComplete(e);            if (UseCheckAllColumn != null)            {                var column = Columns[UseCheckAllColumn];                if (column.Tag != null&&(bool)column.Tag == true)                {                    column.Tag = false;                    InvalidateCell(Columns[UseCheckAllColumn].Index, -1);                }
                }        }

实现效果:

Winform重绘DataGridView选择框