带CheckBox列头的DataGridView(二)

时间:2022-03-14 10:25:44

     上次从CodeProject上发现了一个老外写的开源的带CheckBox列头的类,当时就将文章翻译了过来并做成了一个小Demo,供大家参考,最近在开发中需要用到这个类,因此加以了改进,上次还有一个兄弟提到问怎样实现取消列表中选择的一行,列头的全选CheckBox也能处于不选中状态。这是一个很好的问题,我最近几天花了些时间,将其进行了些修改。终于可以实现这一功能了。废话不多说了,代码如下:

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Windows.Forms;

namespace chbDGV
{
    public delegate void CheckBoxClickedHandler(bool state);

    /// <summary>
    /// 改变列头的CheckBox的状态
    /// </summary>
    /// <param name="state"></param>
    public delegate void ChangeCheckBoxStatusHandler(bool state);

    public class DataGridViewCheckBoxHeaderCellEventArgs : EventArgs
    {
        bool _bChecked;
        public DataGridViewCheckBoxHeaderCellEventArgs(bool bChecked)
        {
            _bChecked = bChecked;
        }

        public bool Checked
        {
            get { return _bChecked; }
        }
    }


    class DatagridViewCheckBoxHeaderCell : DataGridViewColumnHeaderCell
    {
        Point checkBoxLocation;
        Size checkBoxSize;
        bool _checked = false;
        Point _cellLocation = new Point();
        System.Windows.Forms.VisualStyles.CheckBoxState _cbState =
            System.Windows.Forms.VisualStyles.CheckBoxState.UncheckedNormal;
        public event CheckBoxClickedHandler OnCheckBoxClicked;
        public event ChangeCheckBoxStatusHandler OnChangeCheckBoxStatusHandler;

        public DatagridViewCheckBoxHeaderCell()
        {
        }

        protected override void Paint(System.Drawing.Graphics graphics,
            System.Drawing.Rectangle clipBounds,
            System.Drawing.Rectangle cellBounds,
            int rowIndex,
            DataGridViewElementStates dataGridViewElementState,
            object value,
            object formattedValue,
            string errorText,
            DataGridViewCellStyle cellStyle,
            DataGridViewAdvancedBorderStyle advancedBorderStyle,
            DataGridViewPaintParts paintParts)
        {
            base.Paint(graphics, clipBounds, cellBounds, rowIndex,
                dataGridViewElementState, value,
                formattedValue, errorText, cellStyle,
                advancedBorderStyle, paintParts);
            Point p = new Point();
            Size s = CheckBoxRenderer.GetGlyphSize(graphics,
            System.Windows.Forms.VisualStyles.CheckBoxState.UncheckedNormal);
            p.X = cellBounds.Location.X +
                (cellBounds.Width / 2) - (s.Width / 2);
            p.Y = cellBounds.Location.Y +
                (cellBounds.Height / 2) - (s.Height / 2);
            _cellLocation = cellBounds.Location;
            checkBoxLocation = p;
            checkBoxSize = s;
            if (_checked)
                _cbState = System.Windows.Forms.VisualStyles.
                    CheckBoxState.CheckedNormal;
            else
                _cbState = System.Windows.Forms.VisualStyles.
                    CheckBoxState.UncheckedNormal;
            CheckBoxRenderer.DrawCheckBox
            (graphics, checkBoxLocation, _cbState);
        }

        protected override void OnMouseClick(DataGridViewCellMouseEventArgs e)
        {
            Point p = new Point(e.X + _cellLocation.X, e.Y + _cellLocation.Y);
            if (p.X >= checkBoxLocation.X && p.X <=
                checkBoxLocation.X + checkBoxSize.Width
            && p.Y >= checkBoxLocation.Y && p.Y <=
                checkBoxLocation.Y + checkBoxSize.Height)
            {
                _checked = !_checked;
                if (OnCheckBoxClicked != null)
                {
                    OnCheckBoxClicked(_checked);
                    this.DataGridView.InvalidateCell(this);
                }

            }
            base.OnMouseClick(e);
        }

        /// <summary>
        /// 改变列头CheckBox的状态的事件
        /// </summary>
        /// <param name="NewStatus"></param>
        public void OnChangeCheckBoxStatus(bool NewStatus)
        {
            if (OnCheckBoxClicked != null)
            {
                _checked = NewStatus;
                if (OnChangeCheckBoxStatusHandler != null)
                {
                    OnChangeCheckBoxStatusHandler(NewStatus);
                }
                if (this.DataGridView != null)
                {
                    this.DataGridView.InvalidateCell(this);
                }
            }
        }

    }
}

测试的代码如下:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace chbDGV
{
    public partial class frmTestDGV : Form
    {

        DataGridViewCheckBoxColumn colCB = new DataGridViewCheckBoxColumn();
        DatagridViewCheckBoxHeaderCell cbHeader = new DatagridViewCheckBoxHeaderCell();
        DataTable dt = new DataTable();

        public frmTestDGV()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            BindDGV();
        }

        public override void Refresh()
        {

            base.Refresh();
        }

        private void cbHeader_OnCheckBoxClicked(bool Status)
        {
            for (int i = 0; i < dgvTest.Rows.Count; i++)
            {
                dt.Rows[i]["Select"] = Status;
            }
        }

        private void BindDGV()
        {
            dt.Columns.Add("Select");
            dt.Columns.Add("ID");
            dt.Columns.Add("Code");
            dt.Columns.Add("Name");
            dt.Columns.Add("Desc");
            for (int i = 0; i < 5; i++)
            {
                dt.Rows.Add();
                dt.Rows[i][0] = false;
                dt.Rows[i][1] = "100"+i.ToString();
                dt.Rows[i][2] = "Lucy1001"+i.ToString();
                dt.Rows[i][3] = "KateTest"+i.ToString();
                dt.Rows[i][4] = "remark...";
            }

            colCB.HeaderCell = cbHeader;
           
            dgvTest.Columns.Insert(0, colCB);

            cbHeader.OnCheckBoxClicked +=
            new CheckBoxClickedHandler(cbHeader_OnCheckBoxClicked);

            dgvTest.AllowUserToAddRows = false;
            dgvTest.AutoGenerateColumns = false;
            dgvTest.DataSource = dt;


            this.colCB.DataPropertyName = "Select";
            this.ID.DataPropertyName = "ID";
            this.Code.DataPropertyName = "Code";
            this.TestName.DataPropertyName = "Name";
            this.Desc.DataPropertyName = "Desc";
           
        }

        /// <summary>
        /// 点击DataGridView的行
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void dgv_CellClick(object sender, DataGridViewCellEventArgs e)
        {
            DataGridView dgvv = ((DataGridView)sender);
            if (dgvTest.CurrentCell.OwningColumn.DataPropertyName == "Select")
            {
                if (e.RowIndex != -1)
                {
                    this.SetSelected(dgvv, e.RowIndex);
                }
            }
        }

        /// <summary>
        /// 设置DataGridView的选择
        /// </summary>
        /// <param name="dgvb"></param>
        /// <param name="rowIndex"></param>
        private void SetSelected(DataGridView dgvb, int rowIndex)
        {
            if (dgvb.Rows[rowIndex] != null)
            {
                if (dgvb.Rows[rowIndex].Cells[0].Value != null && dgvb.Rows[rowIndex].Cells[0].Value.ToString() != "")
                {
                    bool status = !Convert.ToBoolean(dgvb.Rows[rowIndex].Cells[0].Value);
                    dt.Rows[rowIndex][0] = status;
                    dgvb.Rows[rowIndex].Cells[0].Value = status;
                    for (int i = 0; i < dgvb.Rows.Count; i++)
                    {
                        if (dgvb.Rows[i].Cells[0].Value != null && dgvb.Rows[i].Cells[0].Value.ToString() != "")
                        {
                            status = Convert.ToBoolean(dgvb.Rows[i].Cells[0].Value);
                            if (!status)
                            {
                                cbHeader.OnChangeCheckBoxStatus(status);
                                break;
                            }
                        }
                    }
                    if (status)
                    {
                        cbHeader.OnChangeCheckBoxStatus(status);
                    }
                    dgvb.EndEdit();
                }
                else
                {
                    bool status1 = false;
                    dgvb.Rows[rowIndex].Cells[0].Value = dt.Rows[rowIndex][0].ToString();
                    for (int i = 0; i < dgvb.Rows.Count; i++)
                    {
                        if (dgvb.Rows[i].Cells[0].Value != null && dgvb.Rows[i].Cells[0].Value.ToString() != "")
                        {
                            status1 = Convert.ToBoolean(dgvb.Rows[i].Cells[0].Value);
                            if (!status1)
                            {
                                cbHeader.OnChangeCheckBoxStatus(status1);
                                break;
                            }
                        }
                    }
                    if (status1)
                    {
                        cbHeader.OnChangeCheckBoxStatus(status1);
                    }
                    dgvb.EndEdit();
                }
            }
        }

    }
}

代码比较简单,我就没有加很多注释,也不介绍了。代码我会放在我的资源*大家下载,资源名为:带CheckBox列头有全选择功能的DataGridView二。