Как установить флажок в качестве ColumnHeader для dataGridView - PullRequest
10 голосов
/ 15 мая 2009

Я разрабатываю оконное приложение на C # VS2005. У меня есть dataGridView, в котором первый столбец имеет флажки. Теперь я хочу, чтобы заголовок столбца также был CheckBox, который, если я выберу все Checkboxex в столбце, должен быть выбран. Как я могу это сделать.? Я сослался Код проекта ссылка

Но если я использую это, если я нажму FirstCell (не Заголовок) , все ячейки ниже будут выделены. Но я хочу флажок в заголовке столбца. Как я могу это сделать .?

Ответы [ 6 ]

12 голосов
/ 02 июля 2009

Мне также нужно было иметь CheckBox в заголовке столбца DataGridView. Вот как я это сделал:

  • Создать класс, который наследуется от DataGridViewColumnHeaderCell
  • Внутренне используйте System.Windows.Forms.CheckBox для хранения проверенного состояния и предоставления визуального представления CheckBox в стиле ОС.
  • Используйте Bitmap в качестве буфера и нарисуйте на нем обычный CheckBox (используя CheckBox.DrawToBitmap)
  • Переопределить DataGridViewColumnHeaderCell.Paint и, при необходимости, обновить буфер перед его отрисовкой до Graphics, предоставленного Paint
  • Предоставьте свойство Checked для производного DataGridViewColumnHeaderCell, а также событие CheckedChanged
  • Замените производное DataGridViewColumnHeaderCell в столбце HeaderCell при заполнении DataGridView.
  • Установите и снимите флажок CheckBox, когда щелкается заголовок столбца, только если щелчок мыши находится в пределах CheckBox
  • Реализуйте check-all / uncheck-all вне производного класса, прослушивая событие CheckedChanged, обновляя базовый объект данных и затем вызывая ResetBindings, чтобы обновить DataGridView

Вот класс, который я написал, который является производным от DataGridViewColumnHeaderCell:

class DataGridViewCheckBoxColumnHeaderCell : DataGridViewColumnHeaderCell
{
    private Bitmap buffer;
    private CheckBox checkBox;
    private Rectangle checkBoxBounds;

    public DataGridViewCheckBoxColumnHeaderCell()
    {
        this.checkBox = new CheckBox();
    }

    public event EventHandler CheckedChanged;

    public bool Checked
    {
        get 
        { 
            return this.checkBox.Checked; 
        }

        set
        {
            if (!this.Checked == value)
            {
                this.checkBox.Checked = value;
                if (this.buffer != null)
                {
                    this.buffer.Dispose();
                    this.buffer = null;
                }

                this.OnCheckedChanged(EventArgs.Empty);

                if (this.DataGridView != null)
                {
                    this.DataGridView.Refresh();
                }
            }
        }
    }

    protected override void Paint(
        Graphics graphics, 
        Rectangle clipBounds, 
        Rectangle cellBounds, 
        int rowIndex, 
        DataGridViewElementStates dataGridViewElementState, 
        object value, 
        object formattedValue, 
        string errorText, 
        DataGridViewCellStyle cellStyle, 
        DataGridViewAdvancedBorderStyle advancedBorderStyle, 
        DataGridViewPaintParts paintParts)
    {
        // Passing String.Empty in place of 
        // value and formattedValue prevents 
        // this header cell from having text.

        base.Paint(
            graphics, 
            clipBounds, 
            cellBounds, 
            rowIndex, 
            dataGridViewElementState, 
            String.Empty, 
            String.Empty, 
            errorText, 
            cellStyle, 
            advancedBorderStyle, 
            paintParts);

        if (this.buffer == null 
            || cellBounds.Width != this.buffer.Width
            || cellBounds.Height != this.buffer.Height)
        {
            this.UpdateBuffer(cellBounds.Size);
        }

        graphics.DrawImage(this.buffer, cellBounds.Location);
    }

    protected override Size GetPreferredSize(
        Graphics graphics, 
        DataGridViewCellStyle cellStyle, 
        int rowIndex, 
        Size constraintSize)
    {
        return this.checkBox.GetPreferredSize(constraintSize);
    }

    protected override void OnMouseClick(DataGridViewCellMouseEventArgs e)
    {
        if (e.Button == MouseButtons.Left 
            && this.checkBoxBounds.Contains(e.Location))
        {
            this.Checked = !this.Checked;
        }

        base.OnMouseClick(e);
    }

    private void UpdateBuffer(Size size)
    {
        Bitmap updatedBuffer = new Bitmap(size.Width, size.Height);

        this.checkBox.Size = size;

        if (this.checkBox.Size.Width > 0 && this.checkBox.Size.Height > 0)
        {
            Bitmap renderedCheckbox = new Bitmap(
                this.checkBox.Width, 
                this.checkBox.Height);

            this.checkBox.DrawToBitmap(
                renderedCheckbox, 
                new Rectangle(new Point(), this.checkBox.Size));

            MakeTransparent(renderedCheckbox, this.checkBox.BackColor);
            Bitmap croppedRenderedCheckbox = AutoCrop(
                renderedCheckbox, 
                Color.Transparent);

            // TODO implement alignment, right now it is always
            // MiddleCenter regardless of this.Style.Alignment

            this.checkBox.Location = new Point(
                (updatedBuffer.Width - croppedRenderedCheckbox.Width) / 2, 
                (updatedBuffer.Height - croppedRenderedCheckbox.Height) / 2);

            Graphics updatedBufferGraphics = Graphics.FromImage(updatedBuffer);
            updatedBufferGraphics.DrawImage(
                croppedRenderedCheckbox, 
                this.checkBox.Location);

            this.checkBoxBounds = new Rectangle(
                this.checkBox.Location, 
                croppedRenderedCheckbox.Size);

            renderedCheckbox.Dispose();
            croppedRenderedCheckbox.Dispose();
        }

        if (this.buffer != null)
        {
            this.buffer.Dispose();
        }

        this.buffer = updatedBuffer;
    }

    protected virtual void OnCheckedChanged(EventArgs e)
    {
        EventHandler handler = this.CheckedChanged;
        if (handler != null)
        {
            handler(this, e);
        }
    }

    // The methods below are helper methods for manipulating Bitmaps

    private static void MakeTransparent(Bitmap bitmap, Color transparencyMask)
    {
        int transparencyMaskArgb = transparencyMask.ToArgb();
        int transparentArgb = Color.Transparent.ToArgb();

        List deadColumns = new List();

        for (int x = 0; x = 0; x--)
        {
            if (deadColumns.Count == bitmap.Height)
            {
                break;
            }

            for (int y = bitmap.Height - 1; y >= 0; y--)
            {
                if (deadColumns.Contains(y))
                {
                    continue;
                }

                int pixel = bitmap.GetPixel(x, y).ToArgb();

                if (pixel == transparencyMaskArgb)
                {
                    bitmap.SetPixel(x, y, Color.Transparent);
                }
                else if (pixel != transparentArgb)
                {
                    deadColumns.Add(y);
                    break;
                }
            }
        }
    }

    public static Bitmap AutoCrop(Bitmap bitmap, Color backgroundColor)
    {
        Size croppedSize = bitmap.Size;
        Point cropOrigin = new Point();
        int backgroundColorToArgb = backgroundColor.ToArgb();

        for (int x = bitmap.Width - 1; x >= 0; x--)
        {
            bool allPixelsAreBackgroundColor = true;
            for (int y = bitmap.Height - 1; y >= 0; y--)
            {
                if (bitmap.GetPixel(x, y).ToArgb() != backgroundColorToArgb)
                {
                    allPixelsAreBackgroundColor = false;
                    break;
                }
            }

            if (allPixelsAreBackgroundColor)
            {
                croppedSize.Width--;
            }
            else
            {
                break;
            }
        }

        for (int y = bitmap.Height - 1; y >= 0; y--)
        {
            bool allPixelsAreBackgroundColor = true;
            for (int x = bitmap.Width - 1; x >= 0; x--)
            {
                if (bitmap.GetPixel(x, y).ToArgb() != backgroundColorToArgb)
                {
                    allPixelsAreBackgroundColor = false;
                    break;
                }
            }

            if (allPixelsAreBackgroundColor)
            {
                croppedSize.Height--;
            }
            else
            {
                break;
            }
        }

        for (int x = 0; x = 0 && xWhole = 0)
                {
                    bitmapSection.SetPixel(x, y, bitmap.GetPixel(xWhole, yWhole));
                }
                else
                {
                    bitmapSection.SetPixel(x, y, Color.Transparent);
                }
            }
        }

        return bitmapSection;
    }
}
10 голосов
/ 12 января 2012

Приведенное выше решение является хорошим, но есть и более простой способ! Просто добавьте эти два метода, и тогда вы получите то, что хотите!

Сначала добавьте метод show_chkBox в код и вызовите его в функции onload формы или после создания DataGridView:

 private void show_chkBox()
 {
     Rectangle rect = dataGridView1.GetCellDisplayRectangle(0, -1, true);
     // set checkbox header to center of header cell. +1 pixel to position 
     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);
 }

и тогда у вас будет флажок в заголовке.

Для решения проблемы просто добавьте этот код:

private void checkboxHeader_CheckedChanged(object sender, EventArgs e)
{             
    CheckBox headerBox = ((CheckBox)dataGridView1.Controls.Find("checkboxHeader", true)[0]);
    int index = 0;
    for (int i = 0; i < dataGridView1.RowCount; i++)
    {
        dataGridView1.Rows[i].Cells[0].Value = headerBox.Checked;
    }
}
2 голосов
/ 06 января 2015

Если вы выбираете решение @Ehsan, вы должны знать, что если выбрана ячейка флажка, он не будет обновлять пользовательский интерфейс флажка. После этого вам необходимо вызвать RefreshEdit ().

Это происходит только в том случае, если элемент управления является дочерним элементом таблицы данных. По какой-то причине, когда это дочерний элемент управления, флажки выбранных ячеек не могут обновлять пользовательский интерфейс самостоятельно.

0 голосов
/ 26 марта 2019

Ниже приводится решение, которое сработало для меня, так как решение Ehsaan не проверяло первую строку в DataGridView.

Вызовите метод AddChkBoxHeader_DataGridView() в функции OnLoad вашей формы.

CheckBox checkboxHeader = null;
bool isHeaderCheckBoxClicked = false;
private void AddChkBoxHeader_DataGridView()
{
    Rectangle rect = dgvRecipeSelector.GetCellDisplayRectangle(0, -1, true);
    rect.Y = 10;
    rect.X = rect.Location.X + (rect.Width / 4);            
    checkboxHeader = new CheckBox();
    checkboxHeader.Size = new Size(15,15);
    checkboxHeader.Location = rect.Location;
    dgvRecipeSelector.Controls.Add(checkboxHeader);
    checkboxHeader.MouseClick += new MouseEventHandler(checkboxHeader_CheckedChanged);
}

private void checkboxHeader_CheckedChanged(object sender, EventArgs e)
{            
    HeaderCheckBoxClick((CheckBox)sender);
}

private void HeaderCheckBoxClick(CheckBox headerCheckbox)
{
    isHeaderCheckBoxClicked = true;
    foreach (DataGridViewRow r in dgvRecipeSelector.Rows)
    {
        ((DataGridViewCheckBoxCell)r.Cells[0]).Value = headerCheckbox.Checked;
    }
    dgvRecipeSelector.RefreshEdit();
    isHeaderCheckBoxClicked = false;
}
0 голосов
/ 18 марта 2018

Итак - чтобы установить самый верхний флажок, который не отображается как отмеченный (хотя он и есть), я отредактировал ваше событие следующим образом:

private void checkboxHeader_CheckedChanged (отправитель объекта, EventArgs e) { // CheckBox headerBox = ((CheckBox) dtgv1.Controls.Find ("checkboxHeader", true) [0]);

        var headerBox = (CheckBox)sender;
        var b = headerBox.Checked;
        var c = int.Parse(headerBox.Name.Replace("checkboxHeader", ""));
        for (int i = 0; i < dgvSources_fuzzyID.RowCount; i++)
        {
            dgvSources_fuzzyID.Rows[i].Cells[0].Value = headerBox.Checked;
            ***dgvSources_fuzzyID.RefreshEdit();***
        }
    }

Вот что наконец-то исправило для меня ...

0 голосов
/ 14 апреля 2015

Спасибо Ehsan за простой способ, прекрасно работает для меня. Для проблемы только один CheckBox всегда находится в верхнем левом углу, я добавляю суффикс имени к каждому и решил. Кроме того, я хотел бы немного изменить метод обработки событий, напрямую приведя объект-отправитель, так как он был очень специфичным при создании (если только этот метод не используется для обработки событий другого типа).

private string[] _colLst = columNameArray;
private void AddCheckBoxGridViewHeader()
{
    for (int ndx = 0; ndx < _colLst.Length; ndx++)
    {
        var rect = dtgv1.GetCellDisplayRectangle(ndx, -1, true);
        var x = rect.X + (rect.Width * 4 / 5);
        var y = 3;
        Rectangle nrect = new Rectangle(x, y, rect.Width, rect.Height);
        CheckBox checkboxHeader = new CheckBox();
        checkboxHeader.BackColor = Color.Transparent;
        checkboxHeader.Name = "checkboxHeader" + ndx;
        checkboxHeader.Size = new Size(18, 18);
        checkboxHeader.Location = nrect.Location;
        checkboxHeader.CheckedChanged += new EventHandler(checkboxHeader_CheckedChanged);
        dtgv1.Controls.Add(checkboxHeader);
    }
}

private void checkboxHeader_CheckedChanged(object sender, EventArgs e)
{
    //CheckBox headerBox = ((CheckBox)dtgv1.Controls.Find("checkboxHeader", true)[0]);

    var headerBox = (CheckBox)sender;
    var b = headerBox.Checked;
    var c = int.Parse(headerBox.Name.Replace("checkboxHeader", ""));
    for (int i = 0; i < dtgv1.RowCount; i++)
    {
        dtgv1.Rows[i].Cells[c].Style = new DataGridViewCellStyle(); 
        dtgv1.Rows[i].Cells[c].Style.BackColor = (b)? Color.Salmon : Color.White;
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...