简体   繁体   中英

Checkbox in the header of a DataGridView in any column

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

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.

在此处输入图像描述 Finally, How can I know for example what is the position of the header of the column[3] programatically.... Thanks in advance

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

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

The Answer of 56ka is perfekt for me. I just fix the location (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;
    }

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.

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

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

    }
    private void AddHeaderCheckbox()
    {
        CheckBox cb = new CheckBox();
        // your checkbox size
        cb.Size = new Size(15, 15);

        // datagridview checkbox header column cell size
        var cell = dgv.Columns[0].HeaderCell.Size;

        // calculate location
        cb.Location = new Point((cell.Width - cb.Size.Width) / 2, (cell.Height - cb.Size.Height) / 2);

        dgv.Controls.Add(cb);
    }

I used the dataGridView_CellPainting event.

On that event I put in a conditional statement to set the location of my checkbox within the header cell - eg column 1 row 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.

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

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

add this in the AddHeaderCheckBox function

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

this is another solution for the same problem. All you have to do is calling the constructor like showed following.

new ColocarHeaderCheckBox(dataGridView1, colActivo.Index);

Saludos.

using System;
using System.Drawing;
using System.Windows.Forms;

namespace Util
{
    public class ColocarHeaderCheckBox
    {
        CheckBox headerCheckBox = new CheckBox();
        int columnIndex = 0;
        DataGridView dgv;

        /// <summary>
        /// Coloca un CheckBox en el Header del Datagriview para seleccionar o 
        /// deseleccionar todas las filas a la vez.
        /// </summary>
        /// <param name="dgv"></param>
        /// <param name="columnIndex"></param>

        /// (2022-08-29) Editado por Kong Fan
        /// TODO 
        /// Falta hacer que el cuadro de checkbox pueda cambiar de tamano
        public ColocarHeaderCheckBox(DataGridView dgv, int columnIndex)
        {
            // *** Asegurarse de que sea posible utilizar el HeaderCheckBox
            if (!dgv.ColumnHeadersVisible) return;
            if (!dgv.Columns[columnIndex].Visible) return;
            if (dgv.Columns[columnIndex].CellType != typeof(DataGridViewCheckBoxCell)) return;
            // *** Recibir parámetros
            this.columnIndex = columnIndex;
            this.dgv = dgv;
            // *** Crear el HeaderCheckBox y enlazar eventos
            CrearCheckBox();
            // *** Muestra el estado inicial del HeaderCheckBox
            CambiarEstadoHeaderCheckBox(this.dgv);
            // *** Evento para controlar el scroll horizontal
            dgv.Scroll += new ScrollEventHandler(Dgv_Scrolled);
        }

        private void Dgv_Scrolled(object sender, ScrollEventArgs e)
        {
            if (e.ScrollOrientation == ScrollOrientation.HorizontalScroll)
            {
                // *** Si se mueve el scroll vuelve a crear el control
                dgv.Controls.Remove(headerCheckBox);
                if (!CrearCheckBox()) dgv.Controls.Remove(headerCheckBox);
            }
        }

        private bool CrearCheckBox()
        {
            int anchoCuadro = 14;
            int altoCuadro = 14;
            int anchoCelda = dgv.Columns[columnIndex].Width;
            int altoCelda = dgv.ColumnHeadersHeight;
            // *** Determinar la ubicación de la esquina superior izquierda de las columnas adyacentes
            Point columnaUbicacion = dgv.GetColumnDisplayRectangle(columnIndex, true).Location;
            Point columnaAntesUbicacion = new Point();
            Point columnaDespuesUbicacion = new Point();
            // *** Tomar ubicaciones de columnas antes y despues de la columna designada
            bool tieneAntes = false;
            bool tieneDespues = false;
            for (int i = 0; i < dgv.Columns.Count; i++)
            {
                if (dgv.Columns[i].Visible && i < columnIndex && !tieneAntes)
                {
                    columnaAntesUbicacion = dgv.GetColumnDisplayRectangle(i, true).Location;
                    tieneAntes = true;
                }
                if (dgv.Columns[i].Visible && i > columnIndex && !tieneDespues)
                {
                    columnaDespuesUbicacion = dgv.GetColumnDisplayRectangle(i, true).Location;
                    tieneDespues = true;
                }
            }
            // *** Comprobar si hay espacio para crear el control
            if ((columnaDespuesUbicacion.X - columnaUbicacion.X) < (anchoCelda + anchoCuadro) / 2
                    && dgv.FirstDisplayedScrollingColumnIndex != columnIndex)
                return false;
            if ((dgv.Width - columnaAntesUbicacion.X) < ((anchoCelda + anchoCuadro) / 2))
                return false;
            // *** Centrar la posición del headerCheckBox y el alto de la casilla
            int posicionX = 0;
            if (columnaDespuesUbicacion.X != 0)
                posicionX = columnaDespuesUbicacion.X - (anchoCelda + anchoCuadro) / 2;
            else
                posicionX = columnaUbicacion.X + (anchoCelda - anchoCuadro) / 2;
            if (altoCelda < (altoCuadro - 1)) altoCuadro = altoCelda - 2;
            int posicionY = (altoCelda - altoCuadro) / 2 + 1;
            // *** Agregar el control a la DataGridView
            headerCheckBox.Location = new Point(posicionX, posicionY);
            headerCheckBox.BackColor = Color.White;
            headerCheckBox.Size = new Size(anchoCuadro, altoCuadro);
            headerCheckBox.ThreeState = true;
            dgv.Controls.Add(headerCheckBox);
            //  *** Asignar evento Click al headerCheckBox
            headerCheckBox.Click += new EventHandler(HeaderCheckBox_Clicked);
            //  *** Asignar evento Click a las casillas de datos del DataGridView
            dgv.CellContentClick += new DataGridViewCellEventHandler(DataGridView_CellClick);
            return true;
        }

        private void HeaderCheckBox_Clicked(object sender, EventArgs e)
        {
            // *** Extraer del parámetro el sender.Parent la DataGriView
            DataGridView dgv = (DataGridView)((CheckBox)sender).Parent;
            // *** Necesario para finalizar cualquier edición                                                              
            dgv.EndEdit();
            // *** Recorrer todas las filas de la columna para checkar todos o ninguno
            foreach (DataGridViewRow row in dgv.Rows)
            {
                if (headerCheckBox.CheckState == CheckState.Checked)
                {
                    (row.Cells[columnIndex] as DataGridViewCheckBoxCell).Value = true;
                    headerCheckBox.Checked = true;
                }
                else
                {
                    (row.Cells[columnIndex] as DataGridViewCheckBoxCell).Value = false;
                    headerCheckBox.Checked = false;
                }
            }
        }

        private void DataGridView_CellClick(object sender, DataGridViewCellEventArgs e)
        {
            DataGridView dgv = sender as DataGridView;
            // *** Comprobar si está haciendo Click en la fila correcta
            if (e.RowIndex >= 0 && e.ColumnIndex == columnIndex)
                // *** Cambiar el estado del headerCheckBox
                CambiarEstadoHeaderCheckBox(dgv);
        }

        private void CambiarEstadoHeaderCheckBox(DataGridView dgv)
        {
            int positivos = 0;
            int negativos = 0;
            int totalFilas = dgv.RowCount;
            int contador = 0;
            // *** Recorrer todas las filas y determinar uno de los 3 estados del headerCheckBox
            foreach (DataGridViewRow fila in dgv.Rows)
            {
                contador++;
                if ((bool)fila.Cells[columnIndex].EditedFormattedValue == true)
                {
                    positivos++;
                }
                if ((bool)fila.Cells[columnIndex].EditedFormattedValue == false)
                {
                    negativos++;
                }
            }
            if (totalFilas == contador)
            {
                if (totalFilas == negativos)
                {
                    headerCheckBox.CheckState = CheckState.Unchecked;
                }
                else if (totalFilas == positivos)
                {
                    headerCheckBox.CheckState = CheckState.Checked;
                }
                else
                {
                    headerCheckBox.CheckState = CheckState.Indeterminate;
                }
            }
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM