WinForm+VS2005下ReportViewer的打印问题
来源:互联网 发布:淘宝买家v6 编辑:程序博客网 时间:2024/05/16 08:44
前几天,在做的一个项目中,用VS2005+ReportViewer进行报表套打,原来想的很简单,结果在试用过程中出现了很多问题。
刚开始,非常顺利,经测试打印正常,但一试用问题就出现了。
我开发用的机器的系统是win2003,客户的系统是xp,客户在打印时,打印出来的字都是竖的。我就奇怪了,难道这个操作系统还有关系,我又找了一个xp机器,试了试,结果证实确实和操作系统有关,不知道什么原因!
第一个问题就是ReportViewer自带的打印按钮,第一次单击打印后,打印机没反应,第二次打印,打印机才有反应。这个问题非常令人奇怪,我觉得自己的程序没问题,就到网上搜了搜,结果发现我不是第一个,很多人都碰到了这个问题,而且这个问题ReportViewer的一个bug,是不治之症,我心里凉了半截,不过过了一会,又发现了一个外国人的一个狡猾的方法,代码如下,希望对你有用!
private void reportViewer1_Print(object sender, CancelEventArgs e)
{
e.Cancel = true;
timer1.Start();
}
private void timer1_Tick(object sender, EventArgs e)
{
timer1.Stop();
this.reportViewer1.PrintDialog();
}
这个方法就是用了一个定时器,触发第二次打印。我试了,确实起作用!
第二个问题就是ReportViewer的页面设置问题。我套打的票据的宽度大于高度,所以ReportViewer的页面设置就自动地把打印的方向设置为“横向”,这样最终打印机打印出来的字在票据上是竖的。解决这个问题的方法就是对程序来定义页面设置,于是我又上网搜了搜,结果我仍然不是第一个,更令我心凉的是,这个问题仍然是ReportViewer的bug,是不治之症,看来我只有放弃用ReportViewer了,但我一时又找不到其他的好的打印方法,结果就死马当活马医了。我搜了搜,发现微软在页面设置时,采用的单位是英寸in,于是我也把报表的页面大小的单位用英寸in来表示,结果一试,还真行了,真是奇怪!不过好呆问题是解决了!不过这个方法有个后遗症。我这样改后,在xp可以正常打印了,在win2003下又不行了,看来还得针对操作系统发布不同的版本了,没办法。
第三个问题就是“直接打印”问题了,客户要求票据打印的时候,不需要预览,不需要选择打印机,对于这个问题,我刚开始用了一个基于反射的方法,代码如下:
public static class ReportViewerExt
{
/// <summary>
/// 用默认打印机直接打印。
/// </summary>
/// <param name="reportViewer"></param>
public static void DirectPrint(ReportViewer reportViewer)
{
Type reportViewerType = reportViewer.GetType();
FieldInfo printFieldInfo = reportViewerType.GetField("Print", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetField);
CancelEventHandler printEvent = (CancelEventHandler)printFieldInfo.GetValue(reportViewer);
if (printEvent != null)
{
printEvent(reportViewer, null);
}
Object createEMFDeviceInfo = reportViewerType.InvokeMember("CreateEMFDeviceInfo", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.InvokeMethod, null, reportViewer, new object[] { 1, 1 });
Delegate createAndRegisterStream = Delegate.CreateDelegate(typeof(CreateAndRegisterStream), reportViewer, reportViewerType.GetMethod("CreateStreamEMFPrintOnly", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.InvokeMethod));
Type internalRenderingCompleteDelegateType = reportViewerType.Assembly.GetType("Microsoft.Reporting.WinForms.InternalRenderingCompleteDelegate");
Delegate internalRenderingCompleteDelegate = Delegate.CreateDelegate(internalRenderingCompleteDelegateType, reportViewer, reportViewerType.GetMethod("OnRenderingCompletePrintOnly", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.InvokeMethod));
Type postRenderArgsType = reportViewerType.Assembly.GetType("Microsoft.Reporting.WinForms.PostRenderArgs");
Object postRenderArgs = Activator.CreateInstance(postRenderArgsType, false, true);
Object report = reportViewerType.InvokeMember("Report", BindingFlags.NonPublic | BindingFlags.GetProperty | BindingFlags.Instance, null, reportViewer, null);
Object backgroundThread = reportViewerType.InvokeMember("BackgroundThread", BindingFlags.NonPublic | BindingFlags.GetProperty | BindingFlags.Instance, null, reportViewer, null);
backgroundThread.GetType().InvokeMember("BeginRender", BindingFlags.Public | BindingFlags.InvokeMethod | BindingFlags.Instance, null, backgroundThread, new object[] { "IMAGE", true, createEMFDeviceInfo, createAndRegisterStream, internalRenderingCompleteDelegate, postRenderArgs, report });
Type reportDocumentType = reportViewerType.Assembly.GetType("Microsoft.Reporting.WinForms.ReportPrintDocument");
Object currentReport = reportViewerType.InvokeMember("CurrentReport", BindingFlags.NonPublic | BindingFlags.GetProperty | BindingFlags.Instance, null, reportViewer, null);
Object fileManager = currentReport.GetType().InvokeMember("FileManager", BindingFlags.GetProperty, null, currentReport, null);
Object pageSettings = reportViewerType.InvokeMember("PageSettings", BindingFlags.NonPublic | BindingFlags.GetProperty | BindingFlags.Instance, null, reportViewer, null);
Object pageSettingsClone = ((ICloneable)pageSettings).Clone();
ConstructorInfo constructorInfo = reportDocumentType.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { fileManager.GetType(), pageSettings.GetType() }, null);
PrintDocument document = (PrintDocument)constructorInfo.Invoke(new object[] { fileManager, pageSettingsClone });
document.DocumentName = (String)report.GetType().InvokeMember("DisplayNameForUse", BindingFlags.NonPublic | BindingFlags.GetProperty | BindingFlags.Instance, null, report, null);
document.PrinterSettings = (PrinterSettings)reportViewerType.InvokeMember("CreateDefaultPrintSettings", BindingFlags.NonPublic | BindingFlags.InvokeMethod | BindingFlags.Instance, null, reportViewer, null);
document.PrinterSettings.PrintRange = PrintRange.AllPages;
document.Print();
}
}
这个方法刚开始的时候可以,但自从我把报表的单位从cm换成in之后,就再也不起作用了,我能力有限,不知道咋改,就又上网上搜了搜。这次发现微软官方到提供了解决方法,网址为:http://msdn.microsoft.com/en-us/library/ms252091(VS.80).aspx,我按照它的介绍,比葫芦画瓢,还真实现了,代码如下:
#region 打印
private int m_currentPageIndex;
private IList<Stream> m_streams;
// Routine to provide to the report renderer, in order to
// save an image for each page of the report.
private Stream CreateStream(string name, string fileNameExtension, Encoding encoding, string mimeType, bool willSeek)
{
string filenameext = DateTime.Now.Year.ToString() + DateTime.Now.Day.ToString() + DateTime.Now.Month.ToString() + DateTime.Now.Hour.ToString() + DateTime.Now.Minute.ToString() + DateTime.Now.Second.ToString();
Stream stream = new FileStream(name + "." + fileNameExtension, FileMode.Create);
m_streams.Add(stream);
return stream;
}
// Export the given report as an EMF (Enhanced Metafile) file.
private void Export(LocalReport report)
{
string deviceInfo =
"<DeviceInfo>" +
" <OutputFormat>EMF</OutputFormat>" +
" <PageWidth>7.5in</PageWidth>" +
" <PageHeight>3.66in</PageHeight>" +
" <MarginTop>0in</MarginTop>" +
" <MarginLeft>0in</MarginLeft>" +
" <MarginRight>0in</MarginRight>" +
" <MarginBottom>0in</MarginBottom>" +
"</DeviceInfo>";
Warning[] warnings;
m_streams = new List<Stream>();
report.Render("Image", deviceInfo, CreateStream, out warnings);
foreach (Stream stream in m_streams)
{
stream.Position = 0;
}
}
// Handler for PrintPageEvents
private void PrintPage(object sender, PrintPageEventArgs ev)
{
Metafile pageImage = new Metafile(m_streams[m_currentPageIndex]);
ev.Graphics.DrawImage(pageImage, ev.PageBounds);
m_currentPageIndex++;
ev.HasMorePages = (m_currentPageIndex < m_streams.Count);
}
private void Print()
{
if (m_streams == null || m_streams.Count == 0)
return;
PrintDocument printDoc = new PrintDocument();
//printDoc.PrinterSettings.PrinterName = printDocument1.PrinterSettings.PrinterName;
if (!printDoc.PrinterSettings.IsValid)
{
string msg = String.Format(
"Can't find printer /"{0}/".", "默认打印机!");
MessageBox.Show(msg, "找不到默认打印机");
return;
}
printDoc.PrintPage += new PrintPageEventHandler(PrintPage);
printDoc.Print();
}
private void DirectPrintReport()
{
//直接打印
try
{
LocalReport report = this.reportViewer1.LocalReport;
Export(report);
m_currentPageIndex = 0;
Print();
if (m_streams != null)
{
foreach (Stream stream in m_streams)
stream.Close();
m_streams = null;
}
}
catch (Exception ex)
{
MessageBox.Show("在打印过程中出现异常!");
WlCommon.Log("在打印过程中出现异常:" + ex.Message);
}
//直接退出
this.Close();
}
#endregion
这个方法是先把报表保存成EMF格式的图片,然后再打印图片。这个方法应该比较通用。
经过这一顿折腾,我算是领教了ReportViewer,我的结论就是:ReportViewer在程序中最好仅用来显示报表,打印最好还是用最后介绍的打印方法比较保险!
最后说明一下,好像在VS2008里面好像已经没这个问题了,所以,如果有条件的话,最好用VS2008或更新的。
- WinForm+VS2005下ReportViewer的打印问题
- VS2005中的ReportViewer的使用
- ReportViewer 简单报表的制作,解决导出、打印问题
- reportviewer.printdialog 打印窗口返回值问题
- VS2005水晶报表的横向打印问题
- VS2005 crystalReportviewer 打印问题
- 在vs2005中的ReportViewer(RDLC报表)中使用直接打印功能,在vs2005使用ReportViewer2008[转]
- 在vs2005中的ReportViewer(RDLC报表)中使用直接打印功能,在vs2005使用ReportViewer2008
- 在vs2005中的ReportViewer(RDLC报表)中使用直接打印功能,在vs2005使用ReportViewer2008
- 在vs2005中的ReportViewer(RDLC报表)中使用直接打印功能,在vs2005使用ReportViewer2008
- VS2005中ReportViewer 本地模式下报表呈现 入门示例
- ReportViewer下的RDLC(一)
- ReportViewer下的RDLC(二)
- vs2005 winform 全角/半角问题
- .net winform 打印窗体的方法(摘自VS2005帮助文档);
- VS2005下SDL的编译链接问题
- VS2005下SDL的编译链接问题
- 关于VS2005下中文输出的问题
- js 设置获取当前时间后30 的日期,并格式化
- 与谷歌停止合作只因合同到期
- 构造dt,GridView中添加行
- Mozilla Firefox 3.6.4 RC 发布
- Ubuntu Tweak 0.5.4.1修正版发布
- WinForm+VS2005下ReportViewer的打印问题
- 在C#中实现串口通信
- Oracle 数据导入导出imp/exp命令 10g以上expdp/impdp命令
- 推荐一款T-SQL代码格式化工具
- 带图标的程序菜单(1--002)
- How to get Location Using Location API JSR 179
- FireFox和IE下的select option JS相关操作
- 翻译:测试成熟度模型集成(TMMi)(6)
- 积分