This article is an original post: Zyj10011
Original article address: ASP. net web printing-Ultimate Solution
Author Email: Luandao2000@21cn.com
Comrades who have worked on bs development should have a deep understanding that printing in web programs is no longer as easy to control as in applications. Some inherent characteristics of web programs cause this shortcoming, such: the printer is local, and the file may be on the server; how to control and customize the format, and so on. It has brought us a lot of problems in development. Although there are Crystal Reports and other controls to solve, it is always inconvenient. Of course, someone will study and solve the problem. Here I will give a brief introduction to several popular methods:
1. Print IE directly
You can call the ExecWB method of the window. print or webrower control to print the window. print. It is convenient and convenient, and the client does not need any settings. Some methods can also be used to achieve simple customization, such as creating a template htm file, dynamically creating a hidden frame in js, and generating data using scripts, then write the final result file to the hidden frame printing process. If the processing is good, the results are actually good. It should be enough for simple printing. Here is an actual example to illustrate this method:
During development, you often need to print statistical results to users. For example, a common function is to print business reports: the operator first enters the query conditions and then submits the query results, click print to print the report in the defined format.
In most cases, we bind the query results to the DataGrid and print the DataGrid. In this case, the printing format is generally relatively fixed and simple, and will not be changed after confirmation. Therefore, you can use IE to print directly, but if you call window directly. print to print the result page. Other irrelevant elements on the page will be printed, and the format of the end of the page is not easy to control, therefore, the data to be printed is dynamically written to the hidden frame for printing.
Code example: print the specified DataGrid content in ASP. NET
Here, I borrowed a piece of JavaScript code from Microsoft. The entire JavaScript code is as follows:
// Run the following script to print the specified datagrid:
Var vGridContent; // the content of the DataGrid
Var vHeaderInfo; // The printed header.
Var vTailerInfo; // The End of the printed table
/*
Objective: To write and print hidden frames on the page
Parameters:
The DataGrid handle to be printed by the vDataGrid
Note:
The Code calls the following:
BtPrint. Attributes. Add ("onclick", "return PrintDataGrid (document. all ('sheetlist '))");
The SheetList is the ID of the DataGrid to be printed.
*/
Function PrintDataGrid (vDataGrid)
{
PickupHeaderInfo ();
Document. body. insertAdjacentHTML ("beforeEnd ",
"<Iframe name = printHiddenFrame width = 0 height = 0> </iframe> ");
Var doc = printHiddenFrame.doc ument;
Doc. open ();
Doc. write ("<body onload = \" setTimeout ('parent. onprintHiddenFrame () ', 0) \ "> ");
Doc. write ("<iframe name = printMe width = 0 height = 0> </iframe> ");
Doc. write ("</body> ");
Doc. close ();
CreateHtmlReport (printHiddenFrame. printMe, vDataGrid );
Return false;
}
/*
Purpose: To write the content of the DataGrid into a hidden frame and rewrite the format of the DataGrid.
Parameters:
Handle Of A vHideFrame Hidden Frame
The DataGrid handle to be printed by the vDataGrid
Note:
*/
Function CreateHtmlReport (vHideFrame, vDataGrid)
{
VGridContent = vDataGrid. outerHTML;
// Output the report header information and the extracted table
Var doc = vHideFrame.doc ument;
Doc. open ();
Doc. write ("Doc. write (vHeaderInfo );
Doc. write (vGridContent );
Doc. write ("</body> Doc. close ();
// Reset the table style
VDataGrid. borderColor = "#000000 ";
VDataGrid. width = "100% ";
VDataGrid. style. fontFamily = "Verdana ";
VDataGrid. style. fontSize = "12px ";
VDataGrid. style. borderRight = "2px solid #000000 ";
VDataGrid. style. borderTop = "2px solid #000000 ";
VDataGrid. style. borderLeft = "2px solid #000000 ";
VDataGrid. style. borderBottom = "2px solid #000000 ";
VDataGrid. style. borderCollapse = "collapse ";
// Reset the table Header style
Var TBody = vDataGrid. children (0 );
TBody. children (0). style. fontWeight = "bold ";
TBody. children (0). bgColor = "# E7E7E7 ";
// Replace the page number at the bottom of the original table
Var pageInfo = "<td> NO." + (4-3)/1 + 1) + "Page/total" + "1" + "Page & nbsp; & nbsp; </td> ";
}
// Create the end of the table Header
Function PickupHeaderInfo ()
{
Try
{
// Extract the report title Font Size
Var ReportTitleWithSizeInfo = "<font size = '" + "+ 2" + "'>" + "no-fee user statistics" + "</font>"
Var reportDate = "";
Var reportWriter = "";
Var nowdate = new Date ();
ReportDate = "<B> statistical time </B>:" + nowdate. toLocaleString () + "<br> ";
ReportDate + = "<B> Business Office </B>: Test <br> ";
// Generate Report header information
VHeaderInfo = "VHeaderInfo + = "<title> no fees user statistics </title> "<Body bgcolor = '# ffff' style = 'color: #000000; font-family: Verdana; font-size: 12px; cursor: default'> ";
VHeaderInfo + = "<br> <p align = 'center'> <B>" + ReportTitleWithSizeInfo + "</B> </p> ";
VHeaderInfo + = "<p>" + reportDate;
VHeaderInfo + = reportWriter + "</p> ";
}
Catch (e)
{
Alert ("failed to extract public information of the report. The print operation is canceled! ");
Self. close ();
}
}
// The following script is from msdn
// The code by Captain <cerebrum@iname.com>
// Mead & Company, http://www.meadroid.com/wpm/
// Fake print () for IE4.x
If (! PrintIsNativeSupport ())
Window. print = printFrame;
// Main stuff
Function printFrame (frame, onfinish ){
If (! Frame) frame = window;
If (frame.doc ument. readyState! = "Complete "&&
! Confirm ("The document to print is not downloaded yet! Continue with printing? "))
{
If (onfinish) onfinish ();
Return;
}
If (printIsNativeSupport ()){
/* Focus handling for this scope is IE5Beta workaround,
Shocould be gone with IE5 RTM.
*/
Var focused = document. activeElement;
Frame. focus ();
Frame. self. print ();
If (onfinish) onfinish ();
If (focused &&! Focused. disabled) focused. focus ();
Return;
}
Var eventScope = printGetEventScope (frame );
Var focused = document. activeElement;
Window. printHelper = function (){
ExecScript ("on error resume next: printWB. ExecWB 6, 1", "VBScript ");
PrintFireEvent (frame, eventScope, "onafterprint ");
PrintWB. outerHTML = "";
If (onfinish) onfinish ();
If (focused &&! Focused. disabled) focused. focus ();
Window. printHelper = null;
}
Document. body. insertAdjacentHTML ("beforeEnd ",
"<Object id = \" printWB \ "width = 0 height = 0 \
Classid = \ "clsid: 8856F961-340A-11D0-A96B-00C04FD705A2 \"> </object> ");
PrintFireEvent (frame, eventScope, "onbeforeprint ");
Frame. focus ();
Window. printHelper = printHelper;
SetTimeout ("window. printHelper ()", 0 );
}
// Helpers
Function printIsNativeSupport (){
Var agent = window. navigator. userAgent;
Var I = agent. indexOf ("MSIE") + 5;
Return parseInt (agent. substr (I)> = 5 & agent. indexOf ("5.0b1") <0;
}
Function printFireEvent (frame, obj, name ){
Var handler = obj [name];
Switch (typeof (handler )){
Case "string": frame.exe cScript (handler); break;
Case "function": handler ();
}
}
Function printGetEventScope (frame ){
Var frameset = frame.doc ument. all. tags ("FRAMESET ");
If (frameset. length) return frameset [0];
Return frame.doc ument. body;
}
Function onprintHiddenFrame (){
Function onfinish (){
PrintHiddenFrame. outerHTML = "";
If (window. onprintcomplete) window. onprintcomplete ();
}
PrintFrame (printHiddenFrame. printMe, onfinish );
}
Add btPrint. Attributes. Add ("onclick", "return PrintDataGrid (document. all ('sheetlist')") to Page_Load in the program '))");
Note: SheetList is the ID of the DataGrid to be printed. After the query, btPrint is the ID of the print button on the page.
You can write the above script code in a js file and then reference it in the aspx file, as shown in <script srcenter. js "> </script>: the principle of the above Code is relatively simple. The above code can directly print the content of the specified control on the page, of course, the most is to print the table content, if you need to preview and print. You need to create an empty html file and then dynamically write the content to be printed:
Var preDlg = window. open ("PrintList.htm ");
CreateHtmlReport (preDlg, true );
2. ActiveX Controls
Develop controls by yourself. In this way, many commercial software use this method. After writing controls, it is no longer necessary to use them on the web or in applications. The printing method is very flexible, and basically the web that the program can do can also be done. However, the client needs to install components, which is not easy to deploy.
3.. NET components
Lu Yan wrote a good article "printing general WEB reports using XML", and I believe everyone has read it. The concept is novel and easy to implement. It is indeed a general WEB printing solution. In particular, the XML method is used to describe printed files, which leaves a good interface for future format expansion and is very easy to expand. This printing method is suitable for applications with large format changes and small data volumes. This idea also gave ASP. NET a new idea of printing: custom components to implement flexible printing. Of course, the disadvantages are also obvious: 1. You need to install the NET framework1.0 component on the client. 2. XML parsing is not ideal if the file speed is large. 3. There will be a significant latency when the page is loaded for the first time. Of course, the biggest problem is that the client needs to install components, because most of the systems that use the BS architecture, the client configuration is not too high, 9x operating systems are mostly, if you use this method, it will inevitably cause a lot of trouble for the implementation of the project, so it is best to use the xml method to describe the Printing file, and the client does not need to install any components.
After studying Lu Daxia's code, I came up with an idea: In fact, we don't care about other functions in the Code. The most important thing is the xml parsing and printing. Let's take a look at the namespace System of XmlDocument. xml is not unique to winform. webform can also be used. Let's look at the namespace System of PrintDocument. drawing. printing. After querying MSDN, it is found that the class library webform in this namespace is still usable. Well, we can use the two most concerned webforms. We can write this printing control into a class library and then directly call it in ASP. NET without installing any components on the client.
But then the problem came out: Lu Yan's. the NET component is downloaded to the client for the first time in the page request, so the component can directly use a variety of local resources, such as printers, networks, etc., but our print control is written as a class library by ASP. when the NET program is called, the component is actually running on the server, and its access to server resources will not be faulty, but we also hope that the components running on the server can access client resources, for example, if the printer accessing the client prints the specified content, the printed content may be generated on the server.
This raises a new question: How ASP. NET can access various resources without restrictions. For security reasons, ASP. NET programs run with an ASPNET local user account by default. Because this account does not have any network creden, it is an ANONYMOUS Windows Account (nt authority \ anonymous logon) on the network and does not have the permission to access local resources, therefore, APS must be simulated.. NET program runs as another account.
The ideas have been clearly organized and some implementation steps are briefly described:
A. Compile the print component
Refer to Lu Yan's Code to remove irrelevant parts. Only xml parsing and printing sections are retained. Three member data is added to the PrintControl class:
Public string FileName = ""; // name of the file to be printed
Public string PrinterName = ""; // printer name
Public string ClientIP = ""; // Client IP Address
Add a member function:
Public void PrintPage ()
{
Try
{
Doc. Load (FileName );
// Set the printer name
This. printDocument1.PrinterSettings. PrinterName = ClientIP + PrinterName;
// Add print page event handler
This. printDocument1.PrintPage + = new PrintPageEventHandler (this. pd_PrintPage );
// Print the page
// String tm = User. Identity. Name;
This. printDocument1.Print ();
Error_msg = "printed successfully ";
}
Catch (Exception ex)
{
Error_msg = ex. Message;
}
}
Note: The printer on the client must be shared.
Other xml parsing parts do not need to be moved. After being compiled into a class library. NET references RemotePrint. dll, and put a print button on the page to print the function, reference the RemotePrint namespace in the code, write the Click event as follows:
PrintControl print = new PrintControl ();
Print. PrintPath = Request. PhysicalApplicationPath;
Print. ClientIP = Request. ServerVariables ["REMOTE_ADDR"]
Print. PrinterName = "printer ";
Print. PrintPage ();
Enable User Simulation in Web. Config in ASP. NET:
<Identity impersonate = "true" userName = "1234" password = "1234"/>
The preceding solution must be based on the premise that the server and client are running in the same network segment. However, if you think about it carefully, BS systems with the above printing requirements generally run on the enterprise's internal network, so basically meet the requirements