具有更高推荐缩放比例的监视器上的 RDLC 问题

hak*_*iri 7 .net c# wpf reportviewer rdlc

我在我的 WPF 应用程序中使用 .net framework 4.8,我在 RDLC 上有两种用法。第一个是完全提取的 ReportViewer,它使用来自 postgres 的数据表,第二个只是一个 LocalReport,其中有少量参数呈现为 EMF,并使用默认打印机直接打印。

它们都似乎存在渲染问题,但只是在建议缩放 (RS) > 100% 的显示器上。结果是垂直压缩字母并在它们之间添加一些额外的空间(我可以在再次访问客户端计算机后立即提供示例)。如果我只是在我的 100% RS 显示器上增加缩放比例,那么一切都打印得很好。如果我用 1080p 100% RS 显示器替换 >100% RS 显示器,同样,一切都可以正常打印。与我在 Windows 中设置的缩放比例无关,在显示器上的打印输出 > 100% RS 出来总是一团糟。只需使用 ReportViewer 中的“打印布局”视图即可快速重现问题,导出为 PDF 会产生相同的结果。

由于我有 ReportViewer 和 LocalReport 的直接打印输出,我可以尝试几种不同的方法:

  • 使应用程序 DPIAware/notaware/true/PM 等(还包括清单、App.config 和 App.xaml 更改)
  • 将 ReportViewer 放入 ViewBox
  • 在 DeviceInfo 上使用 DpiX/Y 和 PrintDpiX/Y
  • ScaleTransform 和 DrawImageUnscaled 在 PrintPage 回调中使用和不使用 DeviceInfo 更改
  • Windows 中的无数打印机选项

客户端机器运行在最新的 Windows 10 或接近最新的 Windows 10 上,否则相当空。

它敲响了钟声吗?任何潜在修复的想法?

我很想在我的应用程序中使用 RDLC,为了开发和使用的简单性,但这些问题对于该技术来说确实是不可行的。

代码

没有预览打印输出

用于直接打印单个文档,无需通过参数进行预览。

    class CytologiaPrinter : IDisposable
    {
        private static readonly ILog log = LogManager.GetLogger(typeof(CytologiaPrinter));
        private int m_currentPageIndex;
        private IList<Stream> m_streams;

        private int WizytaID;
        private CytologiaAnkieta Cytologia;

        public CytologiaPrinter(int wizytaID)
        {
            WizytaID = wizytaID;
        }

        public CytologiaPrinter(CytologiaAnkieta cytologia)
        {
            Cytologia = cytologia;
        }

        public void Print()
        {
            try
            {
                CytologiaAnkieta cytologia;
                if (Cytologia == null)
                {
                    cytologia = DBCommunication.fetchCytologia(WizytaID);
                }
                else
                {
                    cytologia = Cytologia;
                }
                if (cytologia != null && cytologia.AnkietaNumer != null && cytologia.AnkietaNumer.Length > 0)
                {
                    LocalReport report = new LocalReport();
                    var cytologie = new List<CytologiaAnkieta>();
                    cytologie.Add(cytologia);
                    ReportDataSource reportDataSource = new ReportDataSource("DataSet1", cytologie);
                    report.DataSources.Add(reportDataSource);
                    report.ReportEmbeddedResource = "Suplement.CytologiaAnkieta.rdlc";

                    var parameters = new List<ReportParameter>();
                    //parameters.Add(...); //setting all parameters omitted for demo
                    report.SetParameters(parameters);
                    m_currentPageIndex = 0;
                    Print(cytologia);
                }
            }
            catch (Exception ex)
            {
                log.Error("Error (" + ex.Message + "), stack:" + ex.StackTrace);
            }
        }

        private Stream CreateStream(string name, string fileNameExtension, Encoding encoding, string mimeType, bool willSeek)
        {
            Stream stream = new MemoryStream();
            m_streams.Add(stream);
            return stream;
        }

        private void Export(LocalReport report)
        {
            string deviceInfo =
              @"<DeviceInfo>
                <OutputFormat>EMF</OutputFormat>
                <PageWidth>29.7cm</PageWidth>
                <PageHeight>21cm</PageHeight>
                <MarginTop>1cm</MarginTop>
                <MarginLeft>1cm</MarginLeft>
                <MarginRight>1cm</MarginRight>
                <MarginBottom>1cm</MarginBottom>
            </DeviceInfo>"; //printing in landscape
            Warning[] warnings;
            m_streams = new List<Stream>();
            report.Render("Image", deviceInfo, CreateStream,
               out warnings);
            if (warnings != null && warnings.Length > 0)
            {
                foreach (var warn in warnings)
                {
                    log.Warn("Cytologia printing issues: " + warn.Message);
                }
            }
            foreach (Stream stream in m_streams)
                stream.Position = 0;
        }

        private void PrintPage(object sender, PrintPageEventArgs ev)
        {
            Metafile pageImage = new
               Metafile(m_streams[m_currentPageIndex]);
            
            Rectangle adjustedRect = new Rectangle(
                ev.PageBounds.Left - (int)ev.PageSettings.HardMarginX,
                ev.PageBounds.Top - (int)ev.PageSettings.HardMarginY,
                ev.PageBounds.Width,
                ev.PageBounds.Height);

            ev.Graphics.FillRectangle(Brushes.White, adjustedRect);

            ev.Graphics.DrawImage(pageImage, adjustedRect);

            m_currentPageIndex++;
            ev.HasMorePages = m_currentPageIndex < m_streams.Count;
        }

        private void Print(CytologiaAnkieta cytologia)
        {
            if (m_streams == null || m_streams.Count == 0)
                throw new Exception("Error: no stream to print.");
            PrintDocument printDoc = new PrintDocument();
            printDoc.DefaultPageSettings.Landscape = true;

            if (!printDoc.PrinterSettings.IsValid)
            {
                throw new Exception("Error: cannot find the default printer.");
            }
            else
            {
                printDoc.PrintPage += new PrintPageEventHandler(PrintPage);
                m_currentPageIndex = 0;
                printDoc.Print();
            }
        }

        public void Dispose()
        {
            if (m_streams != null)
            {
                foreach (Stream stream in m_streams)
                    stream.Close();
                m_streams = null;
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

预览 WinForms

xml

xmlns:rv="clr-namespace:Microsoft.Reporting.WinForms;assembly=Microsoft.ReportViewer.WinForms"
...
<WindowsFormsHost DockPanel.Dock="Bottom" Margin="0 0 0 0" >
    <rv:ReportViewer x:Name="RVDemo"/>
</WindowsFormsHost>
Run Code Online (Sandbox Code Playgroud)

C# 代码部分


        private void RaportGenerate_Click(object sender, RoutedEventArgs e)
        {
            RVDemo.Reset();
            ReportDataSource reportDataSource = new ReportDataSource("Ankiety", DBCommunication.fetchCytologiaAnkietyReport(...));
            RVDemo.LocalReport.DataSources.Add(reportDataSource);
            RVDemo.LocalReport.ReportEmbeddedResource = "Suplement.Cytologie.rdlc";
            var parameters = new List<ReportParameter>();
            //parameters.Add(...); // omitted for demo
            RVDemo.LocalReport.SetParameters(parameters);

            RVDemo.RefreshReport();
        }
Run Code Online (Sandbox Code Playgroud)

Har*_*mer 3

如果没有针对 WPF 应用程序上的 RDLC 缩放问题的修复。

一种可能的解决方法是将文件渲染部分迁移到 RDLC 的 Web 版本,这将忽略屏幕 DPI(据我所知)。

您需要额外的资源来开发它。

但在大多数情况下,一些通用函数就足够了。

那么您的报告应该能够以一致的缩放比例呈现。


Microsoft.ReportViewer.Common(如果WebForms 和 WinForms ReportViewer 都可以使用该库版本,则您可能不需要 ReportViewer.WebForms 的附加项目库。)

这是可能的解决方案:

1) 将库项目添加到您的 WPF 解决方案

该解决方案应使用 .NET Framework 4+。它看起来像这样。

在此输入图像描述

2)通过NuGet下载WebForm版本的RDLC到新库

通过微软寻找Microsoft.ReportViewer.WebForms

Microsoft.ReportViewer.Common将为您安装正确版本的依赖项。

在此输入图像描述

3) 创建通过Web版本的RDLC渲染的代码

创建一个静态类供 WDF 项目使用,这是一个非常简单的示例,供您在继续之前测试它是否有效。

将此类复制到“RLDCRendering”项目中:

using Microsoft.Reporting.WebForms;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace RDLCRendering
{
    public class RDLCRender
    {
        public static byte[] RenderReport(String reportPath, DataTable data)
        {
            Microsoft.Reporting.WebForms.ReportDataSource rdc1 = 
                new Microsoft.Reporting.WebForms.ReportDataSource("DataSet1", data);

            Microsoft.Reporting.WebForms.ReportViewer v1 = new Microsoft.Reporting.WebForms.ReportViewer();
            v1.LocalReport.DataSources.Clear();
            v1.LocalReport.ReportPath = reportPath;
            v1.LocalReport.DataSources.Add(rdc1);

            return v1.LocalReport.Render(format: "PDF", deviceInfo: "");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

该项目看起来像这样:

在此输入图像描述

4) 隐藏WPF版本的报表打印按钮

使用此示例代码隐藏“打印/保存”按钮,以便用户不会使用错误的呈现方法

ReportViewer.ShowPrintButton = false;
ReportViewer.ShowExportButton = false;
Run Code Online (Sandbox Code Playgroud)

在 WDF 页面上添加打印按钮,具体操作方式取决于您。

最终结果是这样的: 在此输入图像描述

单击按钮时添加回调,然后提供我们创建的库所需的所有数据源、报告路径、输出路径。

以下是为您提供的示例代码:

            string connString = "Server=someIP;Database=catalogName;User Id=uid;Password=pwd";
            SqlConnection sqlConn = new SqlConnection(connString);
            SqlDataAdapter sqlDA = new SqlDataAdapter("select top 100 * from samplesData", sqlConn);
            DataTable dt= new DataTable();
            sqlDA.Fill(dt);

            //Important
            Byte[] bytes = RDLCRendering.RDLCRender.RenderReport(@"the path to the report teamplate\Report1.rdlc", dt);

            using (FileStream stream = new FileStream(@"C:\test\test.pdf", FileMode.Create))
            {
                stream.Write(bytes, 0, bytes.Length);
            }
Run Code Online (Sandbox Code Playgroud)

5)验证

您可以根据需要更改输出路径。单击该按钮时,应呈现 PDF 文件并将其保存在您指定的位置。在我的示例中,它位于 C:\test\test.pdf 中。

如果此解决方案适合您,您可以继续向/其他渲染函数添加参数等byte[] RenderReport

然后通过将返回的字节文件发送到打印机或保存到某个本地文件夹并使用其他应用程序打开来处理返回的字节文件。