チェックボックスをdataGridViewのColumnHeaderにする方法

CheckBox も必要でした DataGridView の列ヘッダー 桁。私が行った方法は次のとおりです。

  • DataGridViewColumnHeaderCell を継承するクラスを作成する
  • 内部的に System.Windows.Forms.CheckBox を使用する チェックされた状態を保存し、OS スタイルのビジュアル CheckBox を提供する
  • Bitmap を使用する バッファとして、通常の CheckBox を描画します その上で(CheckBox.DrawToBitmapを使用) )
  • DataGridViewColumnHeaderCell.Paint をオーバーライド 必要に応じて、バッファーを Graphics に描画する前にバッファーを更新します。 Paint 提供
  • 派生した DataGridViewColumnHeaderCell に Checked プロパティを提供する 、および CheckedChanged イベント
  • 派生した DataGridViewColumnHeaderCell を代入します 列の HeaderCell DataGridView のとき が入力されています。
  • CheckBox にチェックを入れて外します 列ヘッダーがクリックされたとき、マウス クリックが CheckBox の境界内にある場合のみ
  • 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;
    }
}

@Ehsan ソリューションを選択した場合、チェックボックスのセルが選択されている場合、チェックボックスの UI が更新されないことを知っておく必要があります。後で RefreshEdit() を呼び出す必要があります。

コントロールが datagridview の子コントロールである場合にのみ発生します。何らかの理由で子コントロールの場合、選択されたセルのチェックボックスは独自に UI を更新できません。