C# 任何列中 DataGridView 标题中的复选框

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/8906575/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-09 05:06:02  来源:igfitidea点击:

Checkbox in the header of a DataGridView in any column

c#.netwinformsdatagridview

提问by Ehsan

Actually I have solved the problem of having checkbox in the header of a DGV, here is the code

其实我已经解决了在DGV的标题中有复选框的问题,这是代码

Rectangle rect = dataGridView1.GetCellDisplayRectangle(0, -1, true);
        rect.Y = 3;
        rect.X = rect.Location.X + (rect.Width/4);
        CheckBox checkboxHeader = new CheckBox();
        checkboxHeader.Name = "checkboxHeader";
        //datagridview[0, 0].ToolTipText = "sdfsdf";
        checkboxHeader.Size = new Size(18, 18);
        checkboxHeader.Location = rect.Location;
        checkboxHeader.CheckedChanged += new EventHandler(checkboxHeader_CheckedChanged);
        dataGridView1.Controls.Add(checkboxHeader);    

Actually First I add a column to my DGV which is a DataGridViewCheckBoxColumn and then in the load of the form adding the code above, my problem is as you can see below for the first column it works great since I can set the rect.X in the code for that column but what about the notifier column how can I know where is the position of the header of this column programmatically since the log column can change through maximizing and this stuffs.

实际上首先我向我的 DGV 添加一个列,它是一个 DataGridViewCheckBoxColumn 然后在表单的加载中添加上面的代码,我的问题是你可以在下面看到第一列它工作得很好,因为我可以设置 rect.X该列的代码,但是通知程序列怎么样,我怎么能以编程方式知道该列标题的位置在哪里,因为日志列可以通过最大化和这些东西来改变。

enter image description hereFinally, How can I know for example what is the position of the header of the column[3] programatically.... Thanks in advance

在此处输入图片说明最后,例如,我如何以编程方式知道列 [3] 标题的位置.... 提前致谢

采纳答案by Nighil

try this

尝试这个

#region GridViewCheckBoxColumn


    [System.Drawing.ToolboxBitmap(typeof(System.Windows.Forms.DataGridViewCheckBoxColumn))]
    public class GridViewCheckBoxColumn : DataGridViewCheckBoxColumn
    {
        #region Constructor

        public GridViewCheckBoxColumn()
        {
            DatagridViewCheckBoxHeaderCell datagridViewCheckBoxHeaderCell = new DatagridViewCheckBoxHeaderCell();

            this.HeaderCell = datagridViewCheckBoxHeaderCell;
            this.Width = 50;

            //this.DataGridView.CellFormatting += new System.Windows.Forms.DataGridViewCellFormattingEventHandler(this.grvList_CellFormatting);
            datagridViewCheckBoxHeaderCell.OnCheckBoxClicked += new CheckBoxClickedHandler(datagridViewCheckBoxHeaderCell_OnCheckBoxClicked);

        }

        #endregion

        #region Methods

        void datagridViewCheckBoxHeaderCell_OnCheckBoxClicked(int columnIndex, bool state)
        {
            DataGridView.RefreshEdit();

            foreach (DataGridViewRow row in this.DataGridView.Rows)
            {
                if (!row.Cells[columnIndex].ReadOnly)
                {
                    row.Cells[columnIndex].Value = state;
                }
            }
            DataGridView.RefreshEdit();
        }



        #endregion
    }

    #endregion

    #region DatagridViewCheckBoxHeaderCell

    public delegate void CheckBoxClickedHandler(int columnIndex, bool state);
    public class DataGridViewCheckBoxHeaderCellEventArgs : EventArgs
    {
        bool _bChecked;
        public DataGridViewCheckBoxHeaderCellEventArgs(int columnIndex, 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 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(e.ColumnIndex, _checked);
                    this.DataGridView.InvalidateCell(this);
                }
            }
            base.OnMouseClick(e);
        }

    }

    #endregion

    #region ColumnSelection

    class DataGridViewColumnSelector
    {
        // the DataGridView to which the DataGridViewColumnSelector is attached
        private DataGridView mDataGridView = null;
        // a CheckedListBox containing the column header text and checkboxes
        private CheckedListBox mCheckedListBox;
        // a ToolStripDropDown object used to show the popup
        private ToolStripDropDown mPopup;

        /// <summary>
        /// The max height of the popup
        /// </summary>
        public int MaxHeight = 300;
        /// <summary>
        /// The width of the popup
        /// </summary>
        public int Width = 200;

        /// <summary>
        /// Gets or sets the DataGridView to which the DataGridViewColumnSelector is attached
        /// </summary>
        public DataGridView DataGridView
        {
            get { return mDataGridView; }
            set
            {
                // If any, remove handler from current DataGridView 
                if (mDataGridView != null) mDataGridView.CellMouseClick -= new DataGridViewCellMouseEventHandler(mDataGridView_CellMouseClick);
                // Set the new DataGridView
                mDataGridView = value;
                // Attach CellMouseClick handler to DataGridView
                if (mDataGridView != null) mDataGridView.CellMouseClick += new DataGridViewCellMouseEventHandler(mDataGridView_CellMouseClick);
            }
        }

        // When user right-clicks the cell origin, it clears and fill the CheckedListBox with
        // columns header text. Then it shows the popup. 
        // In this way the CheckedListBox items are always refreshed to reflect changes occurred in 
        // DataGridView columns (column additions or name changes and so on).
        void mDataGridView_CellMouseClick(object sender, DataGridViewCellMouseEventArgs e)
        {
            if (e.Button == MouseButtons.Right && e.RowIndex == -1 && e.ColumnIndex == 0)
            {
                mCheckedListBox.Items.Clear();
                foreach (DataGridViewColumn c in mDataGridView.Columns)
                {
                    mCheckedListBox.Items.Add(c.HeaderText, c.Visible);
                }                
                int PreferredHeight = (mCheckedListBox.Items.Count * 16) + 7;
                mCheckedListBox.Height = (PreferredHeight < MaxHeight) ? PreferredHeight : MaxHeight;
                mCheckedListBox.Width = this.Width;
                mPopup.Show(mDataGridView.PointToScreen(new Point(e.X, e.Y)));
            }
        }

        // The constructor creates an instance of CheckedListBox and ToolStripDropDown.
        // the CheckedListBox is hosted by ToolStripControlHost, which in turn is
        // added to ToolStripDropDown.
        public DataGridViewColumnSelector()
        {
            mCheckedListBox = new CheckedListBox();
            mCheckedListBox.CheckOnClick = true;
            mCheckedListBox.ItemCheck += new ItemCheckEventHandler(mCheckedListBox_ItemCheck);

            ToolStripControlHost mControlHost = new ToolStripControlHost(mCheckedListBox);
            mControlHost.Padding = Padding.Empty;
            mControlHost.Margin = Padding.Empty;
            mControlHost.AutoSize = false;

            mPopup = new ToolStripDropDown();
            mPopup.Padding = Padding.Empty;
            mPopup.Items.Add(mControlHost);
        }

        public DataGridViewColumnSelector(DataGridView dgv)
            : this()
        {
            this.DataGridView = dgv;
        }

        // When user checks / unchecks a checkbox, the related column visibility is 
        // switched.
        void mCheckedListBox_ItemCheck(object sender, ItemCheckEventArgs e)
        {
            mDataGridView.Columns[e.Index].Visible = (e.NewValue == CheckState.Checked);
        }
    }

    #endregion

回答by 56ka

This solution works for me, it adds the checkbox to the header cell. You just have to implement the "check all" method and eventually a "on column resize" method (for replace checkbox in the center)

这个解决方案对我有用,它将复选框添加到标题单元格中。您只需要实现“全部检查”方法,并最终实现“列调整大小”方法(用于替换中心的复选框)

// Creating checkbox without panel
CheckBox checkbox = new CheckBox();
checkbox.Size = new System.Drawing.Size(15, 15);
checkbox.BackColor = Color.Transparent;

// Reset properties
checkbox.Padding = new Padding(0);
checkbox.Margin = new Padding(0);
checkbox.Text = "";

// Add checkbox to datagrid cell
myDataGrid.Controls.Add(checkbox);
DataGridViewHeaderCell header = myDataGrid.Columns[myColumnWithCheckboxes.Index].HeaderCell;
checkbox.Location = new Point(
    header.ContentBounds.Left + (header.ContentBounds.Right - header.ContentBounds.Left + checkbox.Size.Width) / 2,
    header.ContentBounds.Top + (header.ContentBounds.Bottom - header.ContentBounds.Top + checkbox.Size.Height) / 2
);

回答by Suplanus

The Answer of 56ka is perfekt for me. I just fix the location (2px)

56ka 的答案对我来说是完美的。我只是固定位置(2px)

    private CheckBox ColumnCheckbox(DataGridView dataGridView)
    {
        CheckBox checkBox = new CheckBox();
        checkBox.Size = new Size(15, 15);
        checkBox.BackColor = Color.Transparent;

        // Reset properties
        checkBox.Padding = new Padding(0);
        checkBox.Margin = new Padding(0);
        checkBox.Text = "";

        // Add checkbox to datagrid cell
        dataGridView.Controls.Add(checkBox);
        DataGridViewHeaderCell header = dataGridView.Columns[0].HeaderCell;
        checkBox.Location = new Point(
            (header.ContentBounds.Left +
             (header.ContentBounds.Right - header.ContentBounds.Left + checkBox.Size.Width)
             /2) - 2,
            (header.ContentBounds.Top +
             (header.ContentBounds.Bottom - header.ContentBounds.Top + checkBox.Size.Height)
             /2) - 2);
        return checkBox;
    }

回答by Renathu Cazari

public class DataGridViewEx : DataGridView
{
    Dictionary<DataGridViewColumn, bool> dictionaryCheckBox = new Dictionary<DataGridViewColumn, bool>();

    System.Drawing.Bitmap[] bmCheckBox = new System.Drawing.Bitmap[2];

    bool executarValueChanged = true;

    public DataGridViewEx()
        : base()
    {
        #region CheckBox no header da coluna

        CheckBox chkTemp = new CheckBox();

        chkTemp.AutoSize = true;
        chkTemp.BackColor = System.Drawing.Color.Transparent;
        chkTemp.Size = new System.Drawing.Size(16, 16);
        chkTemp.UseVisualStyleBackColor = false;

        bmCheckBox[0] = new System.Drawing.Bitmap(chkTemp.Width, chkTemp.Height);
        bmCheckBox[1] = new System.Drawing.Bitmap(chkTemp.Width, chkTemp.Height);

        chkTemp.Checked = false;
        chkTemp.DrawToBitmap(bmCheckBox[0], new System.Drawing.Rectangle(0, 0, chkTemp.Width, chkTemp.Height));

        chkTemp.Checked = true;
        chkTemp.DrawToBitmap(bmCheckBox[1], new System.Drawing.Rectangle(0, 0, chkTemp.Width, chkTemp.Height));

        #endregion
    }

    public void CheckBoxHeader(DataGridViewCheckBoxColumn column, bool enabled)
    {
        if (enabled == true)
        {
            if (dictionaryCheckBox.Any(f => f.Key == column) == false)
            {
                dictionaryCheckBox.Add(column, false);
                this.InvalidateCell(column.HeaderCell);
            }
        }
        else
        {
            dictionaryCheckBox.Remove(column);

            this.InvalidateCell(column.HeaderCell);
        }
    }

    protected override void OnCellPainting(DataGridViewCellPaintingEventArgs e)
    {
        base.OnCellPainting(e);

        if (e.ColumnIndex >= 0 && e.RowIndex == -1 && dictionaryCheckBox.Any(f => f.Key == this.Columns[e.ColumnIndex]) == true)
        {
            Bitmap bmp = dictionaryCheckBox[this.Columns[e.ColumnIndex]] == true ? bmCheckBox[1] : bmCheckBox[0];

            Rectangle imageBounds = new Rectangle(new Point(e.CellBounds.Location.X + (e.CellBounds.Width / 2) - (bmp.Size.Width / 2), e.CellBounds.Location.Y + (e.CellBounds.Height / 2) - (bmp.Size.Height / 2)), bmp.Size);

            e.PaintBackground(e.CellBounds, true);
            e.PaintContent(e.CellBounds);
            e.Graphics.DrawImage(bmp, imageBounds);
            e.Handled = true;
        }
    }

    protected override void OnColumnHeaderMouseClick(DataGridViewCellMouseEventArgs e)
    {
        base.OnColumnHeaderMouseClick(e);

        if (dictionaryCheckBox.ContainsKey(this.Columns[e.ColumnIndex]) == true)
        {
            var header = this.Columns[e.ColumnIndex].HeaderCell;
            Bitmap img = dictionaryCheckBox[this.Columns[e.ColumnIndex]] == true ? bmCheckBox[1] : bmCheckBox[0];

            if (e.Button == System.Windows.Forms.MouseButtons.Left &&
               e.Y >= header.ContentBounds.Y + (header.Size.Height / 2) - (img.Height / 2) &&
               e.Y <= header.ContentBounds.Y + (header.Size.Height / 2) + (img.Height / 2) &&
               e.X >= header.ContentBounds.X + (this.Columns[e.ColumnIndex].Width / 2) - (img.Width / 2) &&
               e.X <= header.ContentBounds.X + (this.Columns[e.ColumnIndex].Width / 2) + (img.Width / 2))
            {
                dictionaryCheckBox[this.Columns[e.ColumnIndex]] = !dictionaryCheckBox[this.Columns[e.ColumnIndex]];

                this.InvalidateCell(this.Columns[e.ColumnIndex].HeaderCell);

                executarValueChanged = false;
                for (Int32 i = 0; i < this.Rows.Count; i++)
                {
                    this.Rows[i].Cells[e.ColumnIndex].Value = dictionaryCheckBox[this.Columns[e.ColumnIndex]];
                    this.RefreshEdit();
                }
                executarValueChanged = true;
            }

        }
    }

    protected override void OnRowsAdded(DataGridViewRowsAddedEventArgs e)
    {
        base.OnRowsAdded(e);

        List<DataGridViewColumn> listColunas = this.Columns.Cast<DataGridViewColumn>().Where(f => f.GetType() == typeof(DataGridViewCheckBoxColumn)).ToList();
        foreach (DataGridViewColumn coluna in listColunas)
        {
            if (dictionaryCheckBox.ContainsKey(coluna) == true)
            {
                if (dictionaryCheckBox[coluna] == true)
                {
                    executarValueChanged = false;

                    this.Rows[e.RowIndex].Cells[coluna.Index].Value = true;
                    this.RefreshEdit();

                    executarValueChanged = true;
                }
            }
        }
    }

    protected override void OnRowsRemoved(DataGridViewRowsRemovedEventArgs e)
    {
        base.OnRowsRemoved(e);

        List<DataGridViewColumn> listColunas = this.Columns.Cast<DataGridViewColumn>().Where(f => f.GetType() == typeof(DataGridViewCheckBoxColumn)).ToList();
        foreach (DataGridViewColumn coluna in listColunas)
        {
            if (dictionaryCheckBox.ContainsKey(coluna) == true)
            {
                if (this.Rows.Count == 0)
                {
                    dictionaryCheckBox[coluna] = false;
                    this.InvalidateCell(coluna.HeaderCell);
                }
                else
                {
                    Int32 numeroLinhas = this.Rows.Cast<DataGridViewRow>().Where(f => Convert.ToBoolean(f.Cells[coluna.Index].Value) == true).Count();
                    if (numeroLinhas == this.Rows.Count)
                    {
                        dictionaryCheckBox[coluna] = true;
                        this.InvalidateCell(coluna.HeaderCell);
                    }
                }
            }
        }
    }

    protected override void OnCellValueChanged(DataGridViewCellEventArgs e)
    {
        base.OnCellValueChanged(e);

        if (e.ColumnIndex >= 0 && e.RowIndex >= 0)
        {
            if (dictionaryCheckBox.ContainsKey(this.Columns[e.ColumnIndex]) == true)
            {
                if (executarValueChanged == false)
                {
                    return;
                }

                Boolean existeFalse = this.Rows.Cast<DataGridViewRow>().Any(f => Convert.ToBoolean(f.Cells[e.ColumnIndex].Value) == false);

                if (existeFalse == true)
                {
                    if (dictionaryCheckBox[this.Columns[e.ColumnIndex]] == true)
                    {
                        dictionaryCheckBox[this.Columns[e.ColumnIndex]] = false;
                        this.InvalidateCell(this.Columns[e.ColumnIndex].HeaderCell);
                    }
                }
                else
                {
                    dictionaryCheckBox[this.Columns[e.ColumnIndex]] = true;
                    this.InvalidateCell(this.Columns[e.ColumnIndex].HeaderCell);
                }
            }
        }
    }

    protected override void OnCurrentCellDirtyStateChanged(EventArgs e)
    {
        base.OnCurrentCellDirtyStateChanged(e);

        if (this.CurrentCell is DataGridViewCheckBoxCell)
        {
            this.CommitEdit(DataGridViewDataErrorContexts.Commit);
        }
    }
}

use:

用:

dataGridViewEx1.CheckBoxHeader(dataGridViewEx1.Columns[0] as DataGridViewCheckBoxColumn, true);

dataGridViewEx1.CheckBoxHeader(dataGridViewEx1.Columns[0] as DataGridViewCheckBoxColumn, true);

回答by abraham camhy

I used the dataGridView_CellPainting event.

我使用了 dataGridView_CellPainting 事件。

On that event I put in a conditional statement to set the location of my checkbox within the header cell - e.g. column 1 row 0.

在那个事件中,我放入了一个条件语句来设置我的复选框在标题单元格中的位置 - 例如第 1 列第 0 行。

CellBounds has a number of properties that can be used in setting the location. I took the right of the cell "e.CellBounds.Right" and then subtracted the width of the checkbox to put the checkbox in the right corner of the header cell.

CellBounds 有许多可用于设置位置的属性。我拿了单元格“e.CellBounds.Right”的右边,然后减去复选框的宽度,将复选框放在标题单元格的右上角。

void dataGridView1_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
    {
    if (e.ColumnIndex == 1 && e.RowIndex == 0) 
       {
        TopCheckBox.Left = e.CellBounds.Right - 15;
       }
    }

回答by Hrvoje Batrnek

To me, cleanest solution is from "56ka" and this is my upgrade on it. With this, you retain an ability to sort and see the sort direction and to have a label next to the checkbox, normal checkbox and all it has to offer. Made on .NET Framework 4.0 for DataTable. Works with DataTable and EF.

对我来说,最干净的解决方案来自“56ka”,这是我对它的升级。有了这个,您可以保留排序和查看排序方向的能力,并在复选框、普通复选框及其提供的所有内容旁边有一个标签。在 .NET Framework 4.0 上为 DataTable 制作。适用于 DataTable 和 EF。

public static void AddSelectorColumn(this DataGridView dgv, int width = 50, string columnName = "Selected", Action<DataGridViewColumn> addHeaderCheckBoxOverride = null)
{
    if (dgv.Columns[columnName] == null)
    {
        var dt = dgv.Table();

        var dcol = new DataColumn(columnName, typeof(bool));
        dt.Columns.Add(dcol);

        dt.ColumnChanged += (s, e) =>
        {
            var chCols = e.Row.GetChangedColumns();
            if (chCols.Count == 1 && chCols[0].Equals(dcol))
                e.Row.AcceptChanges();
        };
    }

    var col = dgv.Columns[columnName];
    col.HeaderText = "";
    col.ReadOnly = false;
    col.DisplayIndex = 0;
    if (addHeaderCheckBoxOverride != null)
        addHeaderCheckBoxOverride(col);
    else
        col.AddHeaderCheckBox();
    col.Width = width;
}

public static CheckBox AddHeaderCheckBox(this DataGridViewColumn column, HorizontalAlignment align = HorizontalAlignment.Center, int leftBorderOffset = 0, int rightBorderOffset = 0, Func<object, bool> getValue = null, Action<object, bool> setValue = null)
{
    if (column.DataGridView == null) throw new ArgumentNullException("First you need to add the column to grid.");

    // Creating checkbox without panel
    CheckBox checkbox = new CheckBox();
    checkbox.Name = "chk" + column.Name;
    checkbox.Size = new Size(15, 15);
    checkbox.BackColor = Color.Transparent;
    checkbox.Enabled = !column.ReadOnly;

    // Reset properties
    checkbox.Padding = new Padding(0);
    checkbox.Margin = new Padding(0);
    checkbox.Text = "";

    var changedByUser = true;
    var dgv = column.DataGridView;

    checkbox.CheckedChanged += (s, e) =>
    {
        if (changedByUser)
        {
            try
            {
                changedByUser = false;

                if (dgv.IsCurrentCellInEditMode && dgv.CurrentCell.OwningColumn.Name.Equals(column.Name))
                    dgv.EndEdit();

                var dgvRows = new List<DataGridViewRow>((dgv.SelectedRows.Count < 2 ? (ICollection)dgv.Rows : dgv.SelectedRows).Cast<DataGridViewRow>());

                if (column.IsDataBound)
                {
                    //adding to list because of BindingSource sort by that column
                    var boundItems = new List<object>();
                    var areDataRows = dgvRows.Count < 1 || dgvRows[0].DataBoundItem is DataRowView;
                    if (areDataRows)
                    {
                        foreach (DataGridViewRow row in dgvRows)
                            boundItems.Add(((DataRowView)row.DataBoundItem).Row);
                        foreach (DataRow dr in boundItems)
                        {
                            var val = dr[column.DataPropertyName];
                            if ((val is bool && (bool)val) != checkbox.Checked)
                                dr[column.DataPropertyName] = checkbox.Checked;
                        }
                    }
                    else
                    {
                        foreach (DataGridViewRow row in dgvRows)
                            boundItems.Add(row.DataBoundItem);
                        foreach (var item in boundItems)
                        {
                            var val = getValue(item);
                            if (val != checkbox.Checked)
                                setValue(item, checkbox.Checked);
                        }
                    }
                }
                else
                {
                    foreach (DataGridViewRow dgr in dgvRows)
                    {
                        var cell = dgr.Cells[column.Name];
                        if ((cell.Value is bool && (bool)cell.Value) != checkbox.Checked)
                            cell.Value = checkbox.Checked;
                    }
                }
            }
            finally
            {
                changedByUser = true;
            }
        }
    };

    // Add checkbox to datagrid cell
    dgv.Controls.Add(checkbox);

    Action onColResize = () =>
    {
        var colCheck = dgv.Columns[column.Name];
        if (colCheck == null) return;
        int colLeft = (dgv.RowHeadersVisible ? dgv.RowHeadersWidth : 0) - (colCheck.Frozen ? 0 : dgv.HorizontalScrollingOffset);
        foreach (DataGridViewColumn col in dgv.Columns)
        {
            if (col.DisplayIndex >= colCheck.DisplayIndex) break;
            if (!col.Visible) continue;
            colLeft += col.Width;
        }

        var newPoint = new Point(colLeft, dgv.ColumnHeadersHeight / 2 - checkbox.Height / 2);

        if (align == HorizontalAlignment.Left)
            newPoint.X += 3;
        else if (align == HorizontalAlignment.Center)
            newPoint.X += colCheck.Width / 2 - checkbox.Width / 2;
        else if (align == HorizontalAlignment.Right)
            newPoint.X += colCheck.Width - checkbox.Width - 3;

        var minLeft = colLeft + leftBorderOffset;
        var maxLeft = colLeft + colCheck.Width - checkbox.Width + rightBorderOffset;

        if (newPoint.X < minLeft) newPoint.X = minLeft;
        if (newPoint.X > maxLeft) newPoint.X = maxLeft;

        checkbox.Location = newPoint;
        checkbox.Visible = colCheck.Visible;
    };
    dgv.ColumnWidthChanged += (s, e) => onColResize();
    dgv.ColumnHeadersHeightChanged += (s, e) => onColResize();
    dgv.Scroll += (s, e) => onColResize();
    dgv.Resize += (s, e) => onColResize();
    dgv.Sorted += (s, e) => onColResize();
    dgv.RowHeadersWidthChanged += (s, e) => onColResize();
    dgv.ColumnStateChanged += (s, e) => onColResize();

    Action<object> onDataChanged = (e) =>
    {
        if (!changedByUser) return;
        if (e is DataColumnChangeEventArgs)
        {
            if (!((DataColumnChangeEventArgs)e).Column.ColumnName.Equals(column.Name))
                return;
        }
        else if (e is ListChangedEventArgs)
        {
            var prop = ((ListChangedEventArgs)e).PropertyDescriptor;
            if (prop != null && !prop.Name.Equals(column.DataPropertyName))
                return;
        }

        bool allAreTrue = true;
        foreach (DataGridViewRow row in dgv.SelectedRows.Count < 2 ? (ICollection)dgv.Rows : dgv.SelectedRows)
        {
            var val = row.Cells[column.Name].Value;
            if (!(val is bool) || !(bool)val)
            {
                allAreTrue = false;
                break;
            }
        }

        try
        {
            changedByUser = false;
            var tag = checkbox.Tag;
            checkbox.Tag = "AUTO";
            try
            {
                checkbox.Checked = allAreTrue;
            }
            finally { checkbox.Tag = tag; }
        }
        finally
        {
            changedByUser = true;
        }
    };
    dgv.SelectionChanged += (s, e) => onDataChanged(e);
    if (dgv.DataSource is BindingSource)
        ((BindingSource)dgv.DataSource).ListChanged += (s, e) => onDataChanged(e);
    else if (dgv.DataSource is DataSet)
        ((DataSet)dgv.DataSource).Tables[dgv.DataMember].ColumnChanged += (s, e) => onDataChanged(e);
    else if (dgv.DataSource is DataTable)
        ((DataTable)dgv.DataSource).ColumnChanged += (s, e) => onDataChanged(e);

    return checkbox;
}

回答by Ch'nycos

Hove missed something when you remove a column and add another at the same index

当您删除一列并在同一索引处添加另一列时,Hove 错过了一些东西

add this in the AddHeaderCheckBox function

在 AddHeaderCheckBox 函数中添加这个

 Action onColRemoved = () =>
 {
     checkbox.Dispose();
 };
 dgv.ColumnRemoved += (s, e) => onColRemoved();

and modify this :

并修改这个:

foreach (DataGridViewRow row in dgv.SelectedRows.Count < 2 ? (ICollection) dgv.Rows : dgv.SelectedRows)
{ 
    var val = row.Cells[column.Name].Value;
    if (!(val is bool) || !(bool) val)
    {
        allAreTrue = false;
        break;
    }
}

into this

进入这个

foreach (DataGridViewRow row in dgv.SelectedRows.Count < 2 ? (ICollection) dgv.Rows : dgv.SelectedRows)
{
    if (dgv.Columns.Contains(column.Name))
    {
        var val = row.Cells[column.Name].Value;
        if (!(val is bool) || !(bool) val)
        {
            allAreTrue = false;
            break;
        }
    }
}

回答by Hadi Salehy

You must call the event click on the column By identifying the column you clicked, you can access the desired row and change the value of the corresponding field for example:

您必须调用单击该列的事件通过识别您单击的列,您可以访问所需的行并更改相应字段的值,例如:

    private void dataGridViewOrderState_CellClick(object sender, DataGridViewCellEventArgs e)
    {
        if (e.ColumnIndex == dataGridViewOrderState.Columns["selectedDataGridViewCheckBoxColumn"].Index)
        {
            var bid = dataGridViewOrderState.Rows[e.RowIndex];
            var selectedRow = (OrderStateLocal)bid.DataBoundItem;
            if (selectedRow == null)
                return;
            selectedRow.Selected = !selectedRow.Selected;
        }

    }