You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

VB.NET下ReportViewer打印SSRS报表仅出第一页的完整解决方案请求

SSRS报表打印仅输出第一页的完整解决方案(VB.NET/C#)

问题场景

在Windows窗体中使用ReportViewer组件,通过VB.NET代码直接打印SSRS报表时,仅能打印第一页,现有代码片段如下:

现有VB.NET代码片段

Try
    doc = New Printing.PrintDocument()
    AddHandler doc.PrintPage, AddressOf PrintPageHandler
    doc.DefaultPageSettings.Landscape = False

    Dim deviceInfo As String =
                "<DeviceInfo>" &
        "<OutputFormat>emf</OutputFormat>" &
        "  <PageWidth>8.3in</PageWidth>" &
        "  <PageHeight>11.7in</PageHeight>" &
        "  <MarginTop>0.14in</MarginTop>" &
        "  <MarginLeft>0.22in</MarginLeft>" &
        "  <MarginRight>0.22in</MarginRight>" &
        "  <MarginBottom>0.14in</MarginBottom>" &
        "  <StartPage>0</StartPage>" &
        "  <EndPage>10</EndPage>" &
        "</DeviceInfo>"

    Dim warnings() As Microsoft.Reporting.WinForms.Warning
    Dim streamids() As String
    Dim mimeType As String, encoding As String, filenameExtension As String
    mimeType = "" : encoding = "" : filenameExtension = ""

    Dim data() As Byte
    data = ReportViewer1.ServerReport.Render("Image", deviceInfo, mimeType, encoding, filenameExtension, streamids, warnings)
    pages.Add(New Metafile(New MemoryStream(data)))

    For Each pageName As String In streamids
        data = ReportViewer1.ServerReport.RenderStream("Image", pageName, deviceInfo, mimeType, encoding)
        pages.Add(New Metafile(New MemoryStream(data)))
    Next

    doc.Print()
Catch ex As Exception
    ' 异常处理
End Try
Private Sub PrintPageHandler(ByVal sender As Object, ByVal e As PrintPageEventArgs)
    fnName = "PrintPageHandler"
    Try
        Dim page As Metafile = pages(pageIndex)
        pageIndex += 1
        Dim pWidth As Integer = 827
        Dim pHeight As Integer = 1100
        e.Graphics.DrawImage(page, 0, 0, pWidth, pHeight)
        e.HasMorePages = pageIndex < pages.Count
    Catch ex As Exception
        ' 异常处理
    End Try
End Sub

问题根源

  1. 状态未正确重置:pageIndex未在打印前重置为0,多次打印会导致起始索引错误;pages集合未清空,可能残留旧页面数据。
  2. 页面范围限制:原deviceInfo中固定设置<EndPage>10</EndPage>,若报表页数不足或超出此范围会导致打印异常。
  3. 事件重复绑定:未移除旧的PrintPage事件处理器,多次触发会引发逻辑混乱。

VB.NET完整解决方案

' 类级别变量声明
Private pages As New List(Of Metafile)()
Private pageIndex As Integer = 0
Private doc As Printing.PrintDocument

Private Sub PrintSSRSReport()
    Try
        ' 重置打印状态,避免旧数据干扰
        pages.Clear()
        pageIndex = 0
        doc = New Printing.PrintDocument()
        
        ' 先移除旧事件处理器,防止重复绑定
        RemoveHandler doc.PrintPage, AddressOf PrintPageHandler
        AddHandler doc.PrintPage, AddressOf PrintPageHandler

        doc.DefaultPageSettings.Landscape = False

        ' 设备信息配置:EndPage设为-1表示打印所有页面
        Dim deviceInfo As String = "<DeviceInfo>" &
                                    "<OutputFormat>emf</OutputFormat>" &
                                    "<PageWidth>8.3in</PageWidth>" &
                                    "<PageHeight>11.7in</PageHeight>" &
                                    "<MarginTop>0.14in</MarginTop>" &
                                    "<MarginLeft>0.22in</MarginLeft>" &
                                    "<MarginRight>0.22in</MarginRight>" &
                                    "<MarginBottom>0.14in</MarginBottom>" &
                                    "<StartPage>0</StartPage>" &
                                    "<EndPage>-1</EndPage>" &
                                    "</DeviceInfo>"

        Dim warnings() As Microsoft.Reporting.WinForms.Warning
        Dim streamids() As String
        Dim mimeType As String = "", encoding As String = "", filenameExtension As String = ""

        ' 渲染第一页
        Dim data() As Byte = ReportViewer1.ServerReport.Render("Image", deviceInfo, mimeType, encoding, filenameExtension, streamids, warnings)
        pages.Add(New Metafile(New MemoryStream(data)))

        ' 渲染剩余所有页面
        For Each pageName As String In streamids
            data = ReportViewer1.ServerReport.RenderStream("Image", pageName, deviceInfo, mimeType, encoding)
            pages.Add(New Metafile(New MemoryStream(data)))
        Next

        ' 执行打印
        doc.Print()

    Catch ex As Exception
        MessageBox.Show("打印失败:" & ex.Message)
    End Try
End Sub

Private Sub PrintPageHandler(ByVal sender As Object, ByVal e As PrintPageEventArgs)
    Try
        ' 无剩余页面则终止打印
        If pageIndex >= pages.Count Then
            e.HasMorePages = False
            Return
        End If

        Dim page As Metafile = pages(pageIndex)
        pageIndex += 1

        ' 按打印页面实际尺寸绘制,避免固定尺寸导致失真
        Dim pageRect As New Rectangle(0, 0, e.PageBounds.Width, e.PageBounds.Height)
        e.Graphics.DrawImage(page, pageRect)

        ' 判断是否还有后续页面
        e.HasMorePages = pageIndex < pages.Count

    Catch ex As Exception
        MessageBox.Show("打印页处理失败:" & ex.Message)
        e.HasMorePages = False
    End Try
End Sub

C#完整解决方案

// 类级别变量声明
private List<Metafile> pages = new List<Metafile>();
private int pageIndex = 0;
private PrintDocument doc;

private void PrintSSRSReport()
{
    try
    {
        // 重置打印状态
        pages.Clear();
        pageIndex = 0;
        doc = new PrintDocument();

        // 移除旧事件处理器,防止重复绑定
        doc.PrintPage -= PrintPageHandler;
        doc.PrintPage += PrintPageHandler;

        doc.DefaultPageSettings.Landscape = false;

        // 设备信息配置:EndPage设为-1表示打印所有页面
        string deviceInfo = @"<DeviceInfo>
                                <OutputFormat>emf</OutputFormat>
                                <PageWidth>8.3in</PageWidth>
                                <PageHeight>11.7in</PageHeight>
                                <MarginTop>0.14in</MarginTop>
                                <MarginLeft>0.22in</MarginLeft>
                                <MarginRight>0.22in</MarginRight>
                                <MarginBottom>0.14in</MarginBottom>
                                <StartPage>0</StartPage>
                                <EndPage>-1</EndPage>
                              </DeviceInfo>";

        Warning[] warnings;
        string[] streamids;
        string mimeType = "", encoding = "", filenameExtension = "";

        // 渲染第一页
        byte[] data = reportViewer1.ServerReport.Render("Image", deviceInfo, out mimeType, out encoding, out filenameExtension, out streamids, out warnings);
        pages.Add(new Metafile(new MemoryStream(data)));

        // 渲染剩余所有页面
        foreach (string pageName in streamids)
        {
            data = reportViewer1.ServerReport.RenderStream("Image", pageName, deviceInfo, out mimeType, out encoding);
            pages.Add(new Metafile(new MemoryStream(data)));
        }

        // 执行打印
        doc.Print();
    }
    catch (Exception ex)
    {
        MessageBox.Show($"打印失败:{ex.Message}");
    }
}

private void PrintPageHandler(object sender, PrintPageEventArgs e)
{
    try
    {
        if (pageIndex >= pages.Count)
        {
            e.HasMorePages = false;
            return;
        }

        Metafile page = pages[pageIndex];
        pageIndex++;

        // 按打印页面实际尺寸绘制
        Rectangle pageRect = new Rectangle(0, 0, e.PageBounds.Width, e.PageBounds.Height);
        e.Graphics.DrawImage(page, pageRect);

        // 判断是否还有后续页面
        e.HasMorePages = pageIndex < pages.Count;
    }
    catch (Exception ex)
    {
        MessageBox.Show($"打印页处理失败:{ex.Message}");
        e.HasMorePages = false;
    }
}

关键修复点

  • 将deviceInfo中的<EndPage>设为-1,自动适配报表所有页数。
  • 每次打印前清空pages集合并重置pageIndex,确保打印状态干净。
  • 增加事件处理器的移除逻辑,避免重复绑定导致的异常。
  • 按打印页面的实际边界绘制报表,避免固定尺寸引发的失真或截断问题。

内容的提问来源于stack exchange,提问作者PrakNHS

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.11 17:44:53