DataGridVIew Refresh not correct for added Checkbox in DataGridViewHeaderCell

123 Views Asked by At

I am hoping that someone can shed some light on my issue.

My goal is to take an existing DataGridView with a DataGridCheckBoxColumn and add a CheckBox to its header cell. I found some code while researching my question on StackOverflow and have incorporated it (with some changes) into my existing code.

The class below is the one I derived from the StackOverflow post/example (with some additional modifications):

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

namespace AdvancesDistNCPC
{
    class DGVCheckBoxHeaderCell : DataGridViewColumnHeaderCell
    {
        public readonly CheckBox chkBox;
        ToolTip chkToolTip = new ToolTip();
        private Padding m_ButtonPadding = Padding.Empty;

        public DGVCheckBoxHeaderCell(string sCheckText, Color chkForeColor, Color chkBackColor, int chkBoxWidth = 40, string toolTipText = "")
        {
            chkBox = new CheckBox();// { BackColor = Color.Orange, Width = buttonWidth };
            m_ButtonPadding = new Padding(chkBox.Width + 2, 0, 0, 0);
            chkBox.Checked = false;
            chkBox.Text = sCheckText;
            chkBox.TextAlign = ContentAlignment.MiddleCenter;
            chkBox.ForeColor = chkForeColor;
            chkBox.BackColor = chkBackColor;
            if (toolTipText.Length > 0)
            {
                chkToolTip.SetToolTip(chkBox, toolTipText);
            }
            chkBox.CheckAlign = ContentAlignment.BottomCenter;
            chkBox.CheckedChanged += CheckedChanged;
        }

        public void ReplaceHeaderCell(DataGridViewColumnHeaderCell previousHeader)
        {
            if (previousHeader == null) return;
            SetStandardValues(previousHeader);
            var dgv = previousHeader.DataGridView;
            previousHeader.Dispose();
            dgv.Columns[previousHeader.OwningColumn.Index].HeaderCell = this;
        }

        private void SetStandardValues(DataGridViewColumnHeaderCell previous)
        {
            if (previous == null) return;
            this.Style = previous.Style;
            chkBox.Font = this.Style.Font ?? previous.DataGridView.ColumnHeadersDefaultCellStyle.Font;
            // etc.
        }

        private void CheckedChanged(object sender, EventArgs e)
        {
            OnClick(new DataGridViewCellEventArgs(ColumnIndex, RowIndex));
            //MessageBox.Show("You clicked me");
        }

        protected override void OnDataGridViewChanged()
        {
            if (this.DataGridView == null) return;
            this.DataGridView.Controls.Add(chkBox);
        }

        protected override void Paint(Graphics g, Rectangle clipBounds, Rectangle bounds, int rowIndex, DataGridViewElementStates elementState, object value, object formattedValue, string errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advBorderStyle, DataGridViewPaintParts parts)
        {
            cellStyle.Padding = Padding.Add(m_ButtonPadding, cellStyle.Padding);
            base.Paint(g, clipBounds, bounds, rowIndex, elementState, value, formattedValue, errorText, cellStyle, advBorderStyle, parts);
            chkBox.Location = new Point(bounds.Left, bounds.Top + 2);
            chkBox.Height = bounds.Height - 4;
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                chkBox.MouseClick -= CheckedChanged;
                chkBox.Dispose();
            }
            base.Dispose(disposing);
        }
    }
}

I am instantiating this class after the DataGridView has been created and populated, and after I run through a loop to format the existing columns.

I am using the following routine to insert the header cell:

private void Add_AdvanceDist_ApproveAll_Checkbox(ref DataGridView dgvParm, string colName, string sToolTipText = "")
        {
            try
            {
                int colIndex = GetIndexForColName(dgvParm, colName);
                int firstColIdx = dgvParm.FirstDisplayedScrollingColumnIndex;
                dgvParm.FirstDisplayedScrollingColumnIndex = colIndex;
                var newCheckBoxHeaderCell = new DGVCheckBoxHeaderCell("Approve", Color.White, Color.Green);
                newCheckBoxHeaderCell.ReplaceHeaderCell(dgvParm.Columns[colIndex].HeaderCell);
                dgvParm.InvalidateCell(colIndex, 0);
                dgvParm.Columns[approvedCol].Width = 0;
                dgvParm.Refresh();
                dgvParm.FirstDisplayedScrollingColumnIndex = firstColIdx;
            }
            catch (Exception ex)
            {
            }
        }

The code takes the existing DataGridViewCheckBoxColumn in question, and replaces its HeaderCell with the new DGVCheckBoxHeaderCell instance.

So far, the code appears to work (in that the DataGridViewCheckBoxColumn now contains the DGVCheckBoxHeaderCell).

However, something weird is going on with the refresh/painting of the DataGridView. When it is scrolled horizontally, the following happens:

  1. If the DataGridViewCheckBoxColumn is in view, the HeaderCell stays stationary (i.e., doesn't scroll with the rest of the cells), and
  2. When the DataGridViewCheckBoxColumn disappears from view, then the HeaderCell does finally disappear, but when the DataGridView is scrolled (back in the other direction) so that the DataGridViewCheckBoxColumn is in view again, the HeaderCell is not subsequently painted.

It looks like this:

enter image description here

If I scroll back and forth, the effect within the HeaderCell is like a moving car window, within which the column headers whiz by.

Then, when I click directly on the ``HeaderCell```, it displays this:

enter image description here

which is the result I am expecting to happen automatically.

Obviously, this is a cell painting issue. What I am doing wrong (or not doing at all like I should)?

Any suggestions and/or insights would be greatly appreciated.

Thanks in advance,

Chris Fleetwood [email protected]

0

There are 0 best solutions below