在 C# 中打印 DataGridView 时如何计算单元格高度 [有长文本]

How to calculate cell height [that has long text] when printing DataGridView in C#

我搜索了但没有找到如何设置 the cell height 当单元格有长文本时打印 DataGridView

我没有找到一个专注于如何计算长文本高度的结果。而且我不想使用以正确的单元格高度打印它的第 3 方 DLL 文件。

我使用此代码计算高度,但文本总是被剪切,短文本的单元格高度低于 DGV 上的单元格高度。

var tallestHeight = 0;
foreach (DataGridViewCell cell in GridRow.Cells)
{
    if (!cell.Visible) { continue; }
    var s = e.Graphics.MeasureString(cell.FormattedValue.ToString(), dataGridView1.Font);
    var tempHeight = (int)(s.Height * Math.Ceiling(s.Width / dataGridView1.Columns[cell.ColumnIndex].Width));
    if (tempHeight > tallestHeight)
    {
        tallestHeight = tempHeight;
    }
    tallestHeight = (tallestHeight < 22) ? 22 : tallestHeight;
}
iCellHeight = tallestHeight;

我希望在将 DataGridView 打印到打印机时显示所有单元格中的所有文本而不剪切。长文本增加行高,如果没有长文本,行高保持不变。

我的行高 = 22

Text wrap 对于我的 DataGridView 是 enabled

编辑 1:

这是我的 DataGridView properties

这是我打印 DataGridView 的方式:PrintDGV Class 我使用

我的DGV出现了

打印预览

黄色突出显示的文本不完整全文为 First Middle lastname- some text- 0130011511478- تجربةة 7427/01300/8346584584563846

下面的文字完成。

如何让第一行完整显示?

除了网格设置之外,您还需要使用输出大小来计算每行的足够高度以适合其内容。此外,调用采用 StringFormatMeasureString 方法重载对于获得更准确的结果是必要的。

我在上面的打印输出图像中看到您将 MarginBounds.Width 除以可见单元格。因此,以下内容:


计算


创建一个方法来计算和return每行的适当高度。

// +
using System.Linq;

private int GetRowHeight(
    Graphics g, 
    DataGridViewRow row, 
    Rectangle bounds, 
    StringFormat sf, 
    int minHeight = 22)
{
    var cells = row.Cells.OfType<DataGridViewTextBoxCell>()
        .Where(c => c.Visible);

    if (cells == null) return minHeight;

    var cell = cells.Aggregate((DataGridViewTextBoxCell)null, (x, y) => x != null && 
    x.FormattedValue.ToString().Length > y.FormattedValue.ToString().Length ? x : y);

    if (cell == null) return minHeight;

    var h = g.MeasureString(cell.FormattedValue.ToString(),
        row.DataGridView.Font,
        new SizeF(bounds.Width / cells.Count(), bounds.Height),
        sf).ToSize().Height;

    return Math.Max(h + 6, minHeight); // 6 for top and bottom margins...
}

致电


调用者示例和 class 跟踪打印的变量...

// +
using System.Drawing.Printing;

private int rowIndex;
private int cellCount;
private int pageNumber;
private readonly PrintDocument printDoc;
// ...

// ctor
public YourForm()
{
    InitializeComponent();

    printDoc = new PrintDocument();
    printDoc.PrintPage += OnPrintPage;
}

// Cleanup
private void YourForm_FormClosed(object sender, FormClosedEventArgs e)
{
    printDoc.Dispose();
}

// Preview
private void btnPrintPreview(object sender, EventArgs e) => Print(true);

// Print
private void btnPrint(object sender, EventArgs e) => Print();

// Print Routine
private void Print(bool preview = false)
{
    rowIndex = 0;
    cellCount = 0;
    pageNumber = 0;

    var rows = dataGridView1.Rows
        .Cast<DataGridViewRow>()
        .FirstOrDefault(r => !r.IsNewRow);

    if (rows != null)
        cellCount = rows.Cells
            .OfType<DataGridViewTextBoxCell>()
            .Where(c => c.Visible)
            .Count();

    if (cellCount == 0)
    {
        MessageBox.Show("Nothing to print...");
        return;
    }

    printDoc.DefaultPageSettings.Landscape = true;

    if (preview)
    {
        using (var pd = new PrintPreviewDialog())
        {
                    
            pd.Document = printDoc;
            pd.ShowDialog();
        }
    }
    else
    {
        using (var pd = new PrintDialog())
        {
            pd.Document = printDoc;
            if (pd.ShowDialog() == DialogResult.OK)
                pd.Document.Print();
        }
    }
}

打印


PrintDocument.PrintPage 事件示例。

// +
using System.Drawing.Text;

private void OnPrintPage(object sender, PrintPageEventArgs e)
{
    var w = e.MarginBounds.Width / cellCount;
    var x = e.MarginBounds.X;
    var y = e.MarginBounds.Y;
    int h;
    Rectangle rec;

    using (var sf = new StringFormat())
    {
        sf.Alignment = StringAlignment.Center;
        sf.LineAlignment = StringAlignment.Center;

        // Maybe you need to set this? I see Arabic text in the images.
        // sf.FormatFlags = StringFormatFlags.DirectionRightToLeft;

        e.Graphics.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;

        // Uncomment to print the headers in the first page only.
        //if (pageNumber == 0)
        //{
        h = dataGridView1.RowTemplate.Height;

        foreach (var col in dataGridView1.Columns
        .OfType<DataGridViewTextBoxColumn>()
        .Where(c => c.Visible))
        {
            rec = new Rectangle(x, y, w, h);

            e.Graphics.FillRectangle(Brushes.Gainsboro, rec);
            e.Graphics.DrawString(
                col.HeaderText, 
                col.DataGridView.Font, 
                Brushes.Black, 
                rec, 
                sf);
            e.Graphics.DrawRectangle(Pens.Black, rec);

            x += w;
        }
                    
        x = e.MarginBounds.X;
        y += h;                    
        //}

        for (var i = rowIndex; i < dataGridView1.RowCount; i++)
        {
            var row = dataGridView1.Rows[i];

            if (row.IsNewRow) break;

            h = GetRowHeight(e.Graphics, row, e.MarginBounds, sf);

            if (h > e.MarginBounds.Height)
            {
                MessageBox.Show("Insufficient height.");
                e.Cancel = true;
                return;
            }

            foreach (var cell in row.Cells
                .OfType<DataGridViewTextBoxCell>()
                .Where(c => c.Visible))
            {
                rec = new Rectangle(x, y, w, h);

                if (rec.Bottom > e.MarginBounds.Bottom)
                {
                    pageNumber++;
                    rowIndex = i;
                    e.HasMorePages = true;
                    return;
                }

                e.Graphics.DrawString(
                    cell.FormattedValue.ToString(), 
                    dataGridView1.Font, 
                    Brushes.Black, 
                    rec, 
                    sf);
                e.Graphics.DrawRectangle(Pens.Black, rec);

                x += rec.Width;
            }

            x = e.MarginBounds.X;
            y += h;                    
        }
    }
}

输出