问题描述
我在我的WPF应用程序中使用.Net Framework4.8,我在RDLC上有两个用法。第一个是使用来自Postgres的DataTable的完全获取的ReportViewer,第二个只是一个带有少量呈现为EMF并使用默认打印机直接打印的参数的LocalReport。
它们似乎都有渲染问题,但只是在建议缩放(RS)&>100%的显示器上。结果是垂直挤压字母,并在其间添加一些额外的空间(一旦我再次访问客户端计算机,我就可以提供样本)。如果我在我的100%RS显示器上增加比例,一切都打印得很好。如果我将>;100%RS显示器更换为1080p 100%RS显示器,同样,一切都可以正常打印。在带有>;100%RS显示器的机器上,打印输出总是搞砸了,与我在Windows中设置的缩放无关。只需在ReportViewer中使用"Print Layout"视图即可快速复制问题,而导出为PDF会产生相同的结果。
因为我有ReportViewer和LocalReport的直接打印输出,所以我能够尝试几种不同的方法:
- 制作应用程序DPIAware/Not Aware/True/PM等(还包括清单、App.config和App.xaml更改)
- 将ReportViewer放入Viewbox
- 在DeviceInfo上使用DpiX/Y和PrintDpiX/Y
- 在包含和不包含DeviceInfo更改的PrintPage回调中执行ScaleTransform和DrawImageUnscaled
- Windows中的无数打印机选项
客户端计算机运行在最新的Windows 10或接近最新的Windows上,否则将相当空。
有什么印象吗?有什么可能的修复方法吗?
我很想在我的应用程序中使用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;
}
}
}
XAML
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>
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();
}
推荐答案
如果WPF应用上的RDLC伸缩问题没有可用的修复程序。
一种可能的解决方法是将文件呈现部分迁移到RDLC的Web版本,这将忽略屏幕DPI(据我所知)。
您需要额外的资源才能开发此功能。
但在大多数情况下,几个泛型函数就足够了。
那么您的报表应该能够使用一致性缩放呈现。
(如果ReportViewer.WebForms的Microsoft.ReportViewer.Common
库版本可以由WebForms和WinForms ReportViewer使用,则您可能不需要其他项目库。)
以下是可能的解决方案:
1)将库项目添加到您的WPF解决方案
解决方案应使用.NET Framework4+。它应该是这样的。
2)通过NuGet将RDLC的WebForm版本下载到新库
查找Microsoft的Microsoft.ReportViewer.WebForms
。
将为您安装正确版本的Microsoft.ReportViewer.Common
作为依赖项。
3)创建用于通过RDLC的Web版本呈现的代码
为WDF项目创建一个要使用的静态类,这是一个非常简单的示例,您可以在继续之前测试它是否正常工作。
将此类复制到";RLDCRending";项目中:
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: "");
}
}
}
项目将如下所示:
4)隐藏WPF版本的报表打印按钮
使用此示例代码隐藏打印/保存按钮,以便用户不会使用出错的呈现方法
ReportViewer.ShowPrintButton = false;
ReportViewer.ShowExportButton = false;
在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 teamplateReport1.rdlc", dt);
using (FileStream stream = new FileStream(@"C: est est.pdf", FileMode.Create))
{
stream.Write(bytes, 0, bytes.Length);
}
5)验证
您可以根据需要更改输出路径。单击该按钮时,将呈现一个PDF文件并将其保存在您指定的位置下。在我的示例中,它位于C:est est.pdf.
如果此解决方案对您有效,您可以继续向其他渲染函数byte[] RenderReport
添加参数等。
然后通过将其发送到打印机或保存到某个本地文件夹并使用其他应用程序打开来处理返回的字节文件。
这篇关于建议比例较高的显示器上的RDLC问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!