Estoy en .net framework 4.8 en mi aplicación WPF y tengo dos usos en RDLC. El primero es un ReportViewer completamente obtenido que usa un DataTable de postgres, el segundo es solo un Informe local con una pequeña cantidad de parámetros representados como EMF e impresos directamente con el uso de la impresora predeterminada.
Ambos tienen lo que parecería ser un problema de renderizado, pero solo en monitores que tienen una escala recomendada (RS)> 100%. El resultado es aplastar las letras verticalmente y agregar algo de espacio adicional en el medio (puedo proporcionar muestras tan pronto como vuelva a tener acceso a la máquina del cliente). Si solo aumento la escala en mi monitor 100% RS, todo se imprime bien. Si reemplazo el monitor >100% RS con uno de 1080p 100% RS, nuevamente, todo se imprime bien. Las impresiones en máquinas con monitores con >100 % RS siempre salen desordenadas, independientemente de la escala que configuré en Windows. Los problemas se pueden reproducir rápidamente con solo la vista 'Diseño de impresión' en ReportViewer, exportar a PDF produce los mismos resultados.
Como tengo ReportViewer y una impresión directa de LocalReport, pude probar varios enfoques diferentes:
Las máquinas cliente se ejecutan en la última versión de Windows 10 o cerca de la última y, de lo contrario, están bastante vacías.
¿Te suena de algo? ¿Alguna idea para una posible solución?
Me encantaría usar RDLC en mi aplicación, por la simplicidad de desarrollo y uso, pero esos problemas son realmente un problema para la tecnología.
Se utiliza para imprimir un solo documento directamente sin vista previa de los parámetros.
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; } } } 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> 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(); }El problema es bien conocido, también afecta el rendimiento. La razón es simple:
RDLC fue creado para entregar informes simples como recibo o factura. cualquier cosa más que eso te va a causar muchos problemas y muchos dolores de cabeza.
Hay una solución simple que ofrece el soporte técnico de Microsoft en la web:
Pero todos ellos simplemente ignoran el simple hecho de que RDLC nunca fue diseñado para grandes informes o resoluciones más altas. Solo para documentos como facturas o recibos que son modestos y con una pequeña cantidad de detalles para abordar
Si no hay soluciones disponibles para el problema de escalado de RDLC en la aplicación WPF.
Una posible solución sería migrar la parte de representación de archivos a la versión web de RDLC, que ignoraría la pantalla DPI (hasta donde yo sé).
Necesitará recursos adicionales para desarrollar esto.
Pero unas pocas funciones genéricas serían suficientes, en la mayoría de los casos.
Entonces sus informes deberían poder renderizarse con escalado consistente.
(Es posible que no necesite una biblioteca de proyectos adicional para ReportViewer.WebForms si la versión de la biblioteca Microsoft.ReportViewer.Common puede ser utilizada tanto por WebForms como por WinForms ReportViewer).
Aquí está la posible solución:
1) Agregue un proyecto de biblioteca a su solución WPF
La solución debe usar .NET Framework 4+. Se vería algo como esto.
2) Descargue la versión WebForm de RDLC a la nueva biblioteca a través de NuGet
Busque Microsoft.ReportViewer.WebForms de Microsoft.
Se instalará la versión correcta de Microsoft.ReportViewer.Common como dependencia.
3) Cree el código para renderizar a través de la versión web de RDLC
Cree una clase estática para que la use el proyecto WDF, esta es una muestra muy simple para que pruebe si funciona, antes de continuar.
Copie esta clase en el proyecto "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: ""); } } }El proyecto quedaría así:
4) Ocultar el botón de impresión del informe de la versión WPF
Oculte el botón Imprimir/Guardar con este código de ejemplo para que los usuarios no utilicen el método de representación defectuoso
ReportViewer.ShowPrintButton = false; ReportViewer.ShowExportButton = false;Agregue un botón de impresión en su página WDF, cómo lo hace depende de usted.
El resultado final es algo como esto: 
Agregue una devolución de llamada cuando se haga clic en el botón, luego proporcione toda la fuente de datos necesaria, la ruta del informe, la ruta de salida a la biblioteca que creamos.
El siguiente es un código de muestra para usted:
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); }5) Validar
Puede cambiar la ruta de salida según lo necesite. Cuando se hace clic en el botón, se debe procesar y guardar un archivo PDF en la ubicación que especificó. En mi ejemplo, está en C:\test\test.pdf.
Si esta solución funciona para usted, puede continuar agregando parámetros, etc. a la/otra función de representación byte[] RenderReport .
Luego maneje el archivo de bytes devuelto enviándolo a la impresora o guárdelo en alguna carpeta local y ábralo con otras aplicaciones.