c# DataGridView to Bitmap

Всем привет. Нужно конвертировать таблицу в картинку. Самый очевидный, как по мне способ - каждую отдельную строку "сфотографировать", сохранить в лист и затем соединять в одну большую картинку. Написал вот такой код:

            List<byte[]> rowList = new List<byte[]>(); //здесь сохраняем все строки
            for (int i = 0; i < OrderDataGrid.Rows.Count; i++) //вот тут всё идеально работает и прекрасно сохраняется
            //(исключение - если таблица не влезает вся в экран, вылазит исключение. Пока что, не знаю, как с этим разобраться)
            {
                OrderDataGrid.Rows[i].Selected = true;
                Size dgvSz = OrderDataGrid.ClientSize;
                int rw = OrderDataGrid.Rows[i].Index;
                Rectangle RowRect = OrderDataGrid.GetRowDisplayRectangle(rw, true);
                using (Bitmap bmpDgv = new Bitmap(dgvSz.Width, dgvSz.Height))
                using (Bitmap bmpRow = new Bitmap(RowRect.Width, RowRect.Height))
                {
                    OrderDataGrid.DrawToBitmap(bmpDgv, new Rectangle(Point.Empty, dgvSz));
                    using (Graphics G = Graphics.FromImage(bmpRow))
                    {
                        G.DrawImage(bmpDgv, new Rectangle(Point.Empty, RowRect.Size), RowRect, GraphicsUnit.Pixel);
                        string DesktopFolder = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
                        using (MemoryStream stream = new MemoryStream())
                        {
                            bmpRow.Save(stream, ImageFormat.Bmp);
                            rowList.Add(stream.ToArray());
                        }
                    }
                }
            }
            
            int TotalHeight = (OrderDataGrid.RowCount * OrderDataGrid.RowTemplate.Height) +
                        OrderDataGrid.ColumnHeadersHeight;
            Bitmap result = new Bitmap(OrderDataGrid.ClientSize.Width, TotalHeight);
            result.SetResolution(100, 100);
    
            TypeConverter tc = TypeDescriptor.GetConverter(typeof(Bitmap));
            Graphics g = Graphics.FromImage(result);
            int btmCount = 0; //счётчик bitmap
            for (int y = 0; y < TotalHeight - OrderDataGrid.RowTemplate.Height; y += OrderDataGrid.RowTemplate.Height)
            {//вот тут происходит какая-то странная магия и всё ломается. Не могу понять, в чём дело
            //Он выдаёт мне результат, но это просто 6 пустых строк
                using (Bitmap tempBitmap = (Bitmap)tc.ConvertFrom(rowList[btmCount]))
                {
                    for (int x = 0; x < OrderDataGrid.ClientSize.Width; x += 1)
                    {
                        g.DrawImage(tempBitmap, x, y);
                    }
                }
                btmCount++;
            }
            string DesktopFolder2 = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
            result.Save(Path.Combine(DesktopFolder2 + @"\Folder\", "datagridview.png"), ImageFormat.Png);

result:

введите сюда описание изображения


Ответы (3 шт):

Автор решения: Andrew

Найдено в гугле по первой ссылке по... заголовку этого вопроса

//Изменить высоту к оригинальной
int height = dataGridView1.Height;
dataGridView1.Height = dataGridView1.RowCount * dataGridView1.RowTemplate.Height;

//Создать битмап и врисовать туда DataGridView
Bitmap bitmap = new Bitmap(this.dataGridView1.Width, this.dataGridView1.Height);
dataGridView1.DrawToBitmap(bitmap, new Rectangle(0, 0, this.dataGridView1.Width, this.dataGridView1.Height));

//Изменить DataGridView назад к оригинальному размеру
dataGridView1.Height = height;

//Сохранить в папку
bitmap.Save(@"D:\Images\DataGridView.png");

код взят с: https://www.aspsnippets.com/Articles/Convert-Export-DataGridView-to-Bitmap-PNG-Image-in-Windows-Forms-WinForms-Application-using-C-and-VBNet.aspx

→ Ссылка
Автор решения: Frehzy

Рабочий способ. Работает не очень быстро и немного дёргано, но работает. Если подскажите, как его можно оптимизировать, буду благодарен. (сделал "общим")

    int TotalHeight = (OrderDataGrid.RowCount * OrderDataGrid.RowTemplate.Height) +
                OrderDataGrid.ColumnHeadersHeight;
    Bitmap result = new Bitmap(OrderDataGrid.ClientSize.Width, TotalHeight);
    Graphics g = Graphics.FromImage(result);
    result.SetResolution(100, 100);
    int x = 0;
    int y = 0;
    for (int i = 0; i < OrderDataGrid.Rows.Count; i++)
    {
        OrderDataGrid.Rows[i].Selected = true;
        Size dgvSz = OrderDataGrid.ClientSize;
        int rw = OrderDataGrid.Rows[i].Index;
        Rectangle RowRect = OrderDataGrid.GetRowDisplayRectangle(rw, true);
        using (Bitmap bmpDgv = new Bitmap(dgvSz.Width, dgvSz.Height))
        using (Bitmap bmpRow = new Bitmap(RowRect.Width, RowRect.Height))
        {
            OrderDataGrid.DrawToBitmap(bmpDgv, new Rectangle(Point.Empty, dgvSz));
            using (Graphics G = Graphics.FromImage(bmpRow))
            {
                G.DrawImage(bmpDgv, new Rectangle(Point.Empty, RowRect.Size), RowRect, GraphicsUnit.Pixel);
                g.DrawImage(bmpRow, x, y);
            }
        }
        y += OrderDataGrid.RowTemplate.Height;
        try
        { OrderDataGrid.FirstDisplayedScrollingRowIndex++; }
        catch { }
    }
    string DesktopFolder = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
    result.Save(Path.Combine(DesktopFolder, "datagridview.png"), ImageFormat.Png);
→ Ссылка
Автор решения: Alexander Petrov

Вероятно, это самый простой способ отрисовать весь DataGridView в Bitmap:

using (var form = new Form())
using (var dgv = new DataGridView())
{
    dgv.Parent = form;
    dgv.AutoSize = true;
    dgv.DataSource = source;

    using (var bitmap = new Bitmap(dgv.Width, dgv.Height))
    {
        dgv.DrawToBitmap(bitmap, dgv.Bounds);
        bitmap.Save("datagridview.png", ImageFormat.Png);
    }
}

Если задать свойство AutoSize = true;, то грид увеличится (или уменьшится) так, чтобы вместить все строки. После чего вызов DrawToBitmap даст желаемый результат.

Т. к. нежелательно, чтобы реальный контрол менял размеры на реальной форме (это может привести к пересчёту всего Layout), создаём временную форму и грид.

source - это источник данных (коллекция), к которому делаем привязку. Если у вас не используется Data binding, то нужно у временного грида создать такие же колонки, как у реального и скопировать в него строки.

Что интересно, эту временную форму не обязательно показывать вызовом Show() или ShowDialog(), а гриду обязательно нужно иметь родителя.

→ Ссылка