Как установить флажок в качестве столбцаHeader dataGridView

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

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

Ответ 1

Мне также понадобилось иметь 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;
    }
}

Ответ 2

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

Сначала добавьте метод 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;
    }
}

Ответ 3

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

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

Ответ 4

Спасибо 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;
    }
}