Click here to Skip to main content
13,196,126 members (50,267 online)
Click here to Skip to main content
Add your own
alternative version


72 bookmarked
Posted 1 Aug 2004

Customised ASP.NET Printing for Data Grids

, 1 Aug 2004
Rate this:
Please Sign up or sign in to vote.
A solution to provide custom printing for data grids in ASP.NET


Ever tried to print a data grid in ASP.NET? If you have you would have come up with the problem of the data filtering over onto the next page. The result of which are cut-off words and a grid on the next page without any column headers.

When I came up with this problem I had to find a solution that would give me the flexibility to determine exactly what went on each printed page.

I haven't provided the source code to this article simply because the code is too tailored to my particular application and would be confusing. But bear with the article because what I have done is try provide you with the basic framework for implementing your own solution to this problem.


The solution uses Microsoft's print templates and therefore can only work with IE 5.5 or above. As far as I know this is the only supported environment. If this satisfies your requirements then read on...


The key to the solution is an Active-X control that lives on the ASP.NET page. At the time of writing this article the Active-X is written in C++ but I would like to know if anyone manages to get it to work in C#. The Active-X is instantiated on the ASP.NET page and the parameters are set. The parameters that are needed are as follows:

  • ServerAddress - the name of the computer hosting the ASP.NET pages e.g. server1;
  • XML - the data file e.g. data.xml;
  • Template - the print template file e.g. template.html;

Also on the ASP.NET page are two server variables and a div for the Active-X

<div id="printTemplateObject"></div>
<div id="svServer" style="VISIBILITY: hidden">
<%= Request.ServerVariables["SERVER_NAME"] %></div>
<div id="svURL" style="VISIBILITY: hidden">
<%= Request.ServerVariables["URL"] %></div>

In the onload event we create our Active-X object and pass in the relevant parameters

function CreateObject()
  var server = document.all("svServer");
  var url = document.all("svURL");
  var oText = "";
  var position = url.innerText.lastIndexOf("webApplication");
  var location = url.innerText.substr(0, position + 14);
  location = "http://" + server.innerText + location + "PrintTemplate.dll";

  var printTO = document.all("printTemplateObject");
  if(printTO != null)
    oText += "<OBJECT id=\"printTemplateWindow\" ";
    oText += "style=\"Z-INDEX: 120; LEFT: 0px; WIDTH: 100%;" + 
      " POSITION: absolute; TOP: 800px; HEIGHT: 102px\" ";
    oText += "codebase=\"";
    oText += location;
    oText += "\"";
    oText += "classid=\"clsid:CDF583D3-041E-4D1A-AB51-19CE1D3A56A3\" ";
    oText += "name=\"printTemplateWindow\" ";
    oText += "VIEWASTEXT>";

    oText += "<PARAM NAME=\"ServerAddress\" VALUE=\"//";
    oText += server.innerText;
    oText += "/";
    oText += url.innerText;
    oText += "\">";

    oText += "<PARAM NAME=\"XML\" VALUE=\"";
    oText += "data.xml";
    oText += "\">";

    oText += "<PARAM NAME=\"Template\" VALUE=\"";
    oText += "template.html";
    oText += "\">";
    oText += "</OBJECT>";
    printTO.innerHTML = oText;

The Active-X control has its own user interface and this is why I have set the width and height of the control on the ASP.NET form. The user interface of the Active-X has 2 buttons, where one button directly prints and the other button brings up a print preview window. Example code for the user interface is shown below:

<BODY id=theBody>
<TABLE width="90%" align="center" ID="Table1">
    <TD align="center">
      <BUTTON style="width: 50mm; height: 10mm;"

        onclick='navigate("##print##")' ID="Button1">Print</BUTTON>
    <TD align="center">
      <BUTTON style="width: 50mm; height: 10mm;" 

        onclick='navigate("##preview##")' ID="Button2">Print Preview</BUTTON>

Each button has a special onclick event that navigates to a bogus address. The Active-X then captures the OnBeforeNavigate2 message and does its magic.

void CPrintTemplates::OnBeforeNavigate2(
  IDispatch* pDisp, VARIANT* URL, VARIANT* Flags, 
  VARIANT* TargetFrameName, 
  VARIANT* PostData, VARIANT* Headers, VARIANT_BOOL* Cancel )
  CString strURL(URL->bstrVal);

  IOleCommandTarget *pCmdTarg;
  m_spBrowser->QueryInterface(IID_IOleCommandTarget, (void **)&pCmdTarg);

  VARIANT vTemplatePath;
  V_VT(&vTemplatePath) = VT_BSTR;
  CString path = "http:";
  path += m_bstrServerAddress.Copy();
  path += m_bstrTemplate.Copy();
  path += "?";
  path += m_bstrXML.Copy();
  V_BSTR(&vTemplatePath) = path.AllocSysString();

  if(strURL.Left(9) == "##print##")
    HRESULT hr = pCmdTarg->Exec(&CGID_MSHTML, IDM_PRINT, 
    *Cancel = true;
  else if(strURL.Left(11) == "##preview##")
    *Cancel = true;

What this essentially does is build up the path to the template file (that lives on the server) and adds the data file as a parameter

E.g. http:\\server1\webAplication1\template.html?data.xml

It then calls back to the browser to either print or print preview the template.

Print Templates

The Microsoft Print Templates example application that I linked too at the top of this article does much the same but in a stand-alone application sense. The example allows you to specify a template file and press the 'Print Preview' button. Try selecting the Template7.htm - Building a User Interface' option and press the 'Print Preview' button.

Take a look at the source of template7 and you'll see the main body of the HTML page at the bottom. Above it is the JavaScript that handles the printing side of things. The great thing about this is that as it runs client side we have access to the current printer page size, margins, etc...

Now this doesn't solve my problem of printing data grids as the grid will still spill over onto the next page. If you look at the file template.html you should see that the main difference is in the Init() function.

function Init()
  printingStarted = false;
  if(zoomcontainer != null)
    zoomcontainer.innerText = "";
  // load the xml document
  xmlObj = new ActiveXObject('MSXML2.DOMDocument');
  xmlObj.async = false;

  var templateLocation = document.URL.substr(
    0, document.URL.indexOf("?"));
  var position = templateLocation.lastIndexOf("webApplication1");
  var location = templateLocation.substr(0, position + 8);
  reportFile = location + "/" + 
    document.URL.substr(document.URL.indexOf("?") + 1, 

  if(xmlObj.load(reportFile) == false)
    alert("Failed to load document: " + 
      document.URL.substr(document.URL.indexOf("?") + 1, 
  } = "50%"; = document.body.clientWidth; = "50px"; = 
    document.body.clientHeight -;

  file = GenerateHTMLPages(xmlObj,
    (printer.pageWidth - (printer.marginLeft + printer.marginRight))/100,
    (printer.pageHeight - (printer.marginTop + printer.marginBottom))/100);

  // add in all of the required pages
  pages = Pages();

Firstly, the data.xml file is loaded (based upon the URL). Then the function GenerateHTMLPages (stored in a seperate JavaScript file) is called which compiles the data.xml file into separate HTML files for each printed page (more on this later).

The final stage adds the first page and then relies on the OnRectComplete message coming in. When it does we call AddNewPage to add in the new page. This occurs for each added page until all of the pages have been added. If you look at the Microsoft example template file you'll see that the OnRectComplete messages checks to see if the event is due to contentOverflow. It is this that causes the overflowing of the data grid onto the next page and so on. As we have already generated our HTML pages we don't need to handle this case.

The function GenerateHTMLPages is passed the data file and the available printable area. At this point it really up to you how to implement this.
What I did is navigate through my data file and determine how many rows I wanted to fit on a page based upon a nominal figure of 20mm height for each row. With this I can now generate a totally new HTML page for each printed page and put what I want on it and then save it as a temporary file (shown below). The AddNewPage function handles the picking up of each page automatically based on the page number E.g. output1.HTML, output2.HTML, etc...

// file generateHTML.js
// this method saves the passed HTML text to file
function Save(file, pageNumber, htmlText)
  file = file + pageNumber;
  file = file + ".html"

  var fso = new ActiveXObject("Scripting.FileSystemObject");
  var folder = fso.GetSpecialFolder(2);

  file = folder + "/" + file;
  var a = fso.CreateTextFile(file, true);
  return file;

When it came to Headers and footers I did much the same. I simply wrote a method that returns a HTML string that contains the header and footer information. The print template takes care of the rest of it

function AddHeaderAndFooterToPage(pageNum)
    newHeader = "<DIV CLASS='headerstyle'>" + 
    GenerateHeaderFooterHTML(pageNum, GetHeaderFields(xmlObj)) + "</DIV>";
    newFooter = "<DIV CLASS='footerstyle'>" + 
    GenerateHeaderFooterHTML(pageNum, GetFooterFields(xmlObj)) + "</DIV>";
  if(document != null)
    if(document.all("page" + pageNum) != null)
      document.all("page" + 
        pageNum).insertAdjacentHTML("afterBegin", newHeader); 
      document.all("page" + 
        pageNum).insertAdjacentHTML("beforeEnd", newFooter);

And that's it. Hopefully I haven't missed anything out in terms of the flow of information but as you have probably realised by now there is still alot more for you; the developer; to do in order to get this working on you own system. From my point of view I hope that this serves as a first step for you. This article talks mainly about printing data grids but this is not the end of it. With control of each printed page it is up to you what gets printed.

For reference, a great tutorial on Print Templates is available here.

Points of Interest

Whilst this (in my opinion) is an incredible convoluted route to do in essence something which seems very simple, it is the only way that I have found that gives me the flexibility of client-side customized page-by-page printing. I have certainly learnt a great deal with this code and I hope more that I didn't completely miss the boat on a simpler solution.


  • Version 1 : 27th July 2004 - Original


This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


About the Author

Russ Quinn
Web Developer
Australia Australia
Web developer with 15 years of commercial and industrial experience in the software world.
Now working as a contractor through his own company See his blog here
Personal homepage

You may also be interested in...


Comments and Discussions

QuestionAbility to override IE header footer by user's header/footer Pin
Ha Ta1-Nov-07 4:44
memberHa Ta1-Nov-07 4:44 
Questionhttps messages, avoidable? Pin
TClarke22-Feb-06 23:54
memberTClarke22-Feb-06 23:54 
AnswerRe: https messages, avoidable? Pin
Russ Quinn4-Feb-07 22:40
memberRuss Quinn4-Feb-07 22:40 
GeneralRe: https messages, avoidable? Pin
TClarke4-Feb-07 23:51
memberTClarke4-Feb-07 23:51 
Generalcontrol Pin
Linux Gates12-Feb-06 17:03
memberLinux Gates12-Feb-06 17:03 
GeneralRe: control Pin
Russ Quinn4-Feb-07 23:01
memberRuss Quinn4-Feb-07 23:01 
GeneralUrgent -- Datagrid printing Pin
Whuili_200430-Jan-06 8:55
memberWhuili_200430-Jan-06 8:55 
GeneralRe: Urgent -- Datagrid printing Pin
Russ Quinn4-Feb-07 22:39
memberRuss Quinn4-Feb-07 22:39 
GeneralDoes not work ! Pin
Y.Rakha25-Aug-05 4:42
sussY.Rakha25-Aug-05 4:42 
GeneralRe: Does not work ! Pin
Russq25-Aug-05 4:59
memberRussq25-Aug-05 4:59 
GeneralSomethings not clear ! Pin
koko_7725-Aug-05 4:36
memberkoko_7725-Aug-05 4:36 
GeneralRe: Somethings not clear ! Pin
Russq25-Aug-05 5:05
memberRussq25-Aug-05 5:05 
GeneralExcellent Pin
roncalw2-Jul-05 9:34
memberroncalw2-Jul-05 9:34 
GeneralRe: Excellent Pin
Russq25-Aug-05 4:56
memberRussq25-Aug-05 4:56 
GeneralLooking good but needs to explain how the acitve-x can be created Pin
Thomas Valsø Solberg30-Jun-05 22:31
sussThomas Valsø Solberg30-Jun-05 22:31 
GeneralRe: Looking good but needs to explain how the acitve-x can be created Pin
roncalw2-Jul-05 9:22
memberroncalw2-Jul-05 9:22 
GeneralAbout the dll Pin
MrCopland6-May-05 3:54
memberMrCopland6-May-05 3:54 
GeneralRe: About the dll Pin
Russq25-Aug-05 5:03
memberRussq25-Aug-05 5:03 
GeneralData doesn't appeared in Internet Explorer 6 Pin
papdyo28-Apr-05 23:38
memberpapdyo28-Apr-05 23:38 
GeneralRe: Data doesn't appeared in Internet Explorer 6 Pin
Russ Quinn29-Apr-05 0:08
memberRuss Quinn29-Apr-05 0:08 
GeneralRe: Data doesn't appeared in Internet Explorer 6 Pin
papdyo3-May-05 0:10
memberpapdyo3-May-05 0:10 
GeneralRe: Data doesn't appeared in Internet Explorer 6 Pin
roncalw2-Jul-05 9:26
memberroncalw2-Jul-05 9:26 
GeneralPrint and print preview file on the website without using the File - Print on the IE Pin
samanthan sadralin18-Feb-05 18:57
membersamanthan sadralin18-Feb-05 18:57 
GeneralRe: Print and print preview file on the website without using the File - Print on the IE Pin
chuawenching8-Mar-05 23:23
memberchuawenching8-Mar-05 23:23 

You can use this instead.

mshtml.IHTMLDocument2 doc = (mshtml.IHTMLDocument2) axWebBrowser1.Document;
doc.execCommand("Print", true, 0);

Look at Microsoft HTML object library.


Chua Wen Ching
Visit us at
GeneralRe: Print and print preview file on the website without using the File - Print on the IE Pin
samanthan sadralin13-Mar-05 3:29
membersamanthan sadralin13-Mar-05 3:29 
GeneralChuck Ainslie Pin
lamatj8916-Mar-06 21:17
memberlamatj8916-Mar-06 21:17 
QuestionSolve My problem ? Pin
M.ARAFA7-Dec-04 19:47
memberM.ARAFA7-Dec-04 19:47 
AnswerRe: Solve My problem ? Pin
Russ Quinn8-Dec-04 1:10
memberRuss Quinn8-Dec-04 1:10 
QuestionWhere's the ActiveX control ? Pin
M.ARAFA6-Dec-04 23:29
memberM.ARAFA6-Dec-04 23:29 
AnswerRe: Where's the ActiveX control ? Pin
Russ Quinn7-Dec-04 3:22
memberRuss Quinn7-Dec-04 3:22 
GeneralRe: Where's the ActiveX control ? Pin
M.ARAFA7-Dec-04 20:20
memberM.ARAFA7-Dec-04 20:20 
GeneralRe: Where's the ActiveX control ? Pin
Russ Quinn8-Dec-04 1:03
memberRuss Quinn8-Dec-04 1:03 
GeneralNo Data Displayed !!!!!! Pin
M.ARAFA6-Dec-04 23:22
memberM.ARAFA6-Dec-04 23:22 
GeneralRe: No Data Displayed !!!!!! Pin
Russ Quinn7-Dec-04 3:17
memberRuss Quinn7-Dec-04 3:17 
GeneralSample Needed Pin
Franklin577518-Aug-04 1:51
memberFranklin577518-Aug-04 1:51 
GeneralRe: Sample Needed Pin
Russ Quinn18-Aug-04 5:14
memberRuss Quinn18-Aug-04 5:14 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.171019.1 | Last Updated 2 Aug 2004
Article Copyright 2004 by Russ Quinn
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid