CSDN博客

img waterboy

Automatically Printing Crystal Reports in ASP.NET

发表于2004/10/20 7:31:00  2155人阅读

Introduction

Unlike the Windows Forms CrystalReportViewer toolbar, the web-based CrystalReportViewer toolbar does not include a print button.  For reports that are directly rendered as HTML, the user can simply use the browser's print button.  For reports rendered as PDF or Excel, the user can use the print functionality in either the Acrobat Reader or Excel to print the report.

Most users can figure out how to print the report, but some still need a little help, and in some cases, clients request this as part of their application specs.  In this article, we'll review two methods for automatically printing a Crystal Report using the web-based CrystalReportViewer:  the server side ReportDoucment.PrintToPrinter method, and a small client-side JavaScript that uses the window.print method.  We'll also discuss rendering a report in PDF and allowing the user to print that document as an alternative to the two other methods.  Because of the disconnected nature of web client applications, and security considerations, there isn't a perfect way to make every web-based Crystal Report automatically print.  But, under certain conditions, we can provide this functionality in user-friendly ways.

Using Server-Side ReportDocument.PrintToPrinter Method

This server-based method is documented in the Visual Studio help files.  Open the Help Index, and enter PrintToPrinter in the "Look for:" box.  The syntax for this method is:

 Report.PrintToPrinter(<copies as int>, <collated as True/False>, <startpage as int>, <endpage as int>)

'Collated' in this context has nothing to do with database collation.  Some advanced printers (like copier/printers) will sort each document into its own shelf.  Not every printer supports this functionality, so check the printer dialog before setting to true.  To print the entire report, set startpage and endpage each to 0. 

An example in use might look like

MyReport.PrintToPrinter(1,False,0,0)

One limitation of this method is that a printer name must be specified.  You can set the default printer at design time in the report, and you can change the printer name at run time by setting the ReportDocument.PrintOptions.PrinterName property (the PrintOptions are also where you can assign page margins, portrait/landscape, etc.).  Keep in mind that this method prints from the server itself, not from the client machine.  This means that any printer you wish to use must be accessible from the server.  You cannot print to a client's desktop printer using this method unless that printer is shared on the network and mapped to the server.

If your LAN has networked printers, you can make some guesses as to which printer to assign as the default in each report.  For instance, if the Accounting Department has a departmental printer, that would be a good choice to use for the default in an accounting report.  You can provide users the option to choose a networked printer by enumerating the printers mapped to the server and populating a drop-down list.  The PrinterSettings.InstalledPrinters property returns a collection of installed printers, and can be bound to a DropDownList as below.

DropDownList1.DataSource = System.Drawing.Printing.PrinterSettings.InstalledPrinters
DropDownList1.DataBind()

Again, since this code is executing on the server, this will only enumerate the printers on the server mapped to the System user.  If a printer does not appear in the drop-down list, you need to ensure that it is properly mapped to the System user (see below).

All printers and the .NET Framework need to be mapped to the System user in order for this to work.  This is not a trivial task to configure.  Printers can be mapped to the system account only by editing the registry, and since the Framework is mapped to the System user, you may need to reassign security permissions on files and folders.  This process is outlined in the "Printing Web-Based Reports From the Server" article in the VS .NET help files (look up "Crystal Reports, printing" in the VS help index to link to the articles.) and also in Reference 3 (at the end of this article).  The process is a little too intricate to cover here (leave comments if help is needed, and I can amend the article later).

Client Side JavaScript: window.Print

A second option you have uses the JavaScript window.Print method.  Adding this method to the onLoad event of the BODY tag will trigger the browser to print the current page.  Adding this method to a button.onClick event can also be done, just make sure you are using a standard HTML button and not an ASP.NET button control (if you do use an ASP.NET button control, you'll cause a postback, not execute the JavaScript).  In a future article, we'll look at adding a print button to a custom CrystalReportViewer toolbar that uses this method to print a report.

The window.print method does cause a printer selection window to open.  The user will have a chance to select the printer they want to use and must click the "Print" button to start printing.  There is no way to disable the prompt with JavaScript, so for Netscape and other browsers, users will have to see the dialog.  However, in some versions of Internet Explorer, a call to the ExecWB OLE method from a second browser object can be used to circumvent the print dialog (note: spaces have been added to OBJECT declarations to display the code properly in this article--you should remove the spaces to use the code):

function PrintWindow(){ 
if (navigator.appName == "Microsoft Internet Explorer") { 
     var PrintCommand = '< O B J E C T ID="PrintCommandObject" WIDTH=0 HEIGHT=0 ';
PrintCommand += 'CLASSID="CLSID:8856F961-340A-11D0-A96B-00C04FD705A2">';
     document.body.insertAdjacentHTML('beforeEnd', PrintCommand); 
     PrintCommandObject.ExecWB(6, -1); PrintCommandObject.outerHTML = ""; } 
else { window.print();} }  

The ExecWB method requires IE 5.5 or higher to function.  This script essentially creates another browser object of size 0 at the end of the current page.  This new browser object then issues a print command without prompting the user.

A limitation of the window.Print method is that only the current window will print.  In order to print all pages, you must set the SeparatePages property of your CrystalReportViewer to False when the report is rendered.  For example:

CrystalReportViewer1.SeparatePages=False
CrystalReportViewer1.ReportSource=MyReport

Setting SeparatePages to False will cause the entire report to be shown in the current window.  The user will not have to page through the report, but a lot of scrolling may be required.  Page breaks will appear wherever the browser puts them--there is no way to control where page breaks occur--and the browser may wrap the layout in order for it to fit the printer page dimensions.  Your formatting may be completely lost using the window.Print method if your report is wider than the browser window.

The basic window.Print method also prints everything in the window, including whatever form inputs you have added, and the CrystalReportViewer toolbar.  If you have set SeparatePages= False, you probably don't need the toolbar displayed.

If you do not have any other inputs or buttons on your report page, turning off the toolbar may be all you need to do.  If you did add inputs or other buttons, having them show on the printout will not look very professional. To make the report appear a little more professional, we can enclose the report output in a DIV (by enclosing the CrystalReportViewer in a DIV or Panel) and then print just that DIV using a JavaScript function that opens a new window and includes only the information inside the DIV.  In a future article, we'll look at "skinning" the toolbar so you can have a toolbar and this printing functionality at the same time.  The basic code is shown below (source: Reference 2; note that spaces have been added in some tag names for them to display in this article - you should remove the spaces to use the code):

var gAutoPrint = true; // Flag for whether or not to automatically call the print function
function printSpecial() {
if (document.getElementById != null) {
var html = '/n/n'; 
if (document.getElementsByTagName != null) { 
var headTags = document.getElementsByTagName("head"); 
if (headTags.length > 0) 
html += headTags[0].innerHTML;
} 
html += '/n< / H E A D >/n< B O D Y>/n';
var printReadyElem = document.getElementById("printReady"); 
if (printReadyElem != null) { 
html += printReadyElem.innerHTML; } 
else { 
alert("Could not find the printReady section in the HTML"); return; } 
html += '/n/n'; 
var printWin = window.open("","printSpecial"); 
printWin.document.open(); 
printWin.document.write(html); 
printWin.document.close(); 
if (gAutoPrint) printWin.print(); 
}
else { 
alert("Sorry, the print ready feature is only available in modern browsers."); 
} }

If you want to get really fancy, you can combine the two methods so that a report window will automatically open and print in IE browsers or open and prompt for printing in non-IE browsers.  The combined code is shown below and has been tested in both IE 6.0 and FireFox 0.9 (note: spaces have been inserted into tag names so code will display properly--you should remove the spaces to use the code):

var gAutoPrint = true; // Flag for whether or not to automatically call the print function 
function printSpecial() { 
if (document.getElementById != null) { 
var html = '< H T M L >/n< H E A D >/n'; 
if (document.getElementsByTagName != null) { 
var headTags = document.getElementsByTagName("head"); 
if (headTags.length > 0) html += headTags[0].innerHTML; 
} 
if (gAutoPrint) { 
if (navigator.appName == "Microsoft Internet Explorer") { 
html += '/n/n<'
html += 'B O D Y onLoad="PrintCommandObject.ExecWB(6, -1);">/n'; 
} 
else { 
html += '/n/n< B O D Y >/n'; 
} } 
else { 
html += '/n/n< B O D Y >/n'; 
} 

var printReadyElem = document.getElementById("printReady"); 
if (printReadyElem != null) { 
html += printReadyElem.innerHTML; 
} 
else { 
alert("Could not find the printReady section in the HTML"); 
return; 
}
if (gAutoPrint) { 
if (navigator.appName == "Microsoft Internet Explorer") { 
html += '< O B J E C T ID="PrintCommandObject" WIDTH=0 HEIGHT=0 '
html += 'CLASSID="CLSID:8856F961-340A-11D0-A96B-00C04FD705A2">/n/n'; } 
else { 
html += '/n/n'; 
} } 
else { 
html += '/n/n'; 
} 
var printWin = window.open("","printSpecial"); 
printWin.document.open(); 
printWin.document.write(html); 
printWin.document.close();
if (gAutoPrint) { 
if (navigator.appName != "Microsoft Internet Explorer") { 
printWin.print(); 
}}} 
else { 
alert("Sorry, the print ready feature is only available in modern browsers.");
}} 
Export to PDF

As you may have learned from experience, the output from a CrystalReportViewer does not always look like you had intended.  That is because the output is rendered as HTML and sent to the browser that then generates the web page.  In order to get the exact formatting you want, you should export your reports as PDF documents.  One advantage of doing so is that most users know how to print from the Acrobat Reader.  Also, users can save reports and send them as e-mail attachments.

One downside to this option is that users must start the printing process themselves, which does not solve the problem of minimizing user interaction.  Unfortunately, since a PDF is not a page rendered by the browser, none of the JavaScript tricks above will work for us.  There is no simple way to automatically print an exported Crystal Report in PDF format.

Conclusion and References

If your report is fairly simple, you can use the client-side JavaScript window.Print command and a little scripting magic to come up with a satisfactory solution.  Complex reports generated using the JavaScript window.Print may lose the formatting you desired, and, in non-IE browsers, some user intervention is required to answer the Printer Setup dialog.

In a controlled networked environment, the PrintToPrinter() method may provide all the functionality you need.  Networked printers can be enumerated in a drop-down list, and the the user can choose which printer to use.  Most of the limitations have to do with the Internet being a disconnected medium and browser security, which also limits intranet functionality.  Using the PrintToPrinter method requires editing the registry and remapping the .NET Framework user context and limits printing to networked printers.

Printing Crystal Reports is not a process that can be easily automated in a very satisfactory manner.   There is no single magic solution to fit every need; you will need to see which option works best in each situation.  Future versions of Crystal Reports .NET may contain additional functionality, and there are additional tricks we can use in Crystal Reports 10 that will be looked at in a future article.

References

1) "ExecWB Method", http://msdn.microsoft.com/library/default.asp?url=/workshop/browser/webbrowser/reference/methods/execwb.asp

2) "Print Ready Page Script", http://javascript.about.com/library/scripts/blprintready.htm

3) "Printing Web based reports with Crystal Reports for Visual Studio .NET", http://support.businessobjects.com/communityCS/TechnicalPapers/crnet_web_app_printing.pdf.asp

阅读全文
0 0

相关文章推荐

img
取 消
img