Jonas Follesø profile picture

Jonas Follesø

Software Developer

Printing in Silverlight 2 using CSS and ASP.NET AJAX 4

October 13th 2008

One of the frequently asked questions on forums, blogs and by conference attendees is how implement printing in Silverlight applications. Out of the box Silverlight 2 does not have any printer specific APIs, and it’s up to you as the developer to figure out how to deal with printing. If you use the print button in Internet Explorer 7 to print you’ll get a simple rendering of the page. If you try to print from Firefox or Safari you’ll get nothing but a blank page. Printing is a core requirement in many business applications and something you need to be addressed if you’re going to build a Silverlight 2 application. In this blog post I’m going to cover different strategies for printing, and show how we can use the HTML Bridge combined with some of the new features in ASP.NET AJAX 4.0 to implement printing from a Silverlight 2 application.

Print Preview of Silverlight content in IE7

Print preview from the Dive Log application. The Silverlight control is stretched since the container is sized to 100% width and height, and the print preview is in portrait mode. This is probably not what the user wants to print anyway.

Printing strategies

When dealing with printing in Silverlight, or perhaps in web applications in general, you have two main options; generating printouts server side or client side.

When building applications you often want to have printout reports that differ from the actual markup making up the UI of the application. In those cases a common solution for printing is to open a pop-up window that contains a server generated report ready to print. The report can be in any format depending on your requirements. You can show a PDF or XPS document, a Word document, or just a plain HTML document. When implementing server side generation of reports you are not limited to what’s available in the browser, and can choose whatever technology you want. You can use plain ASP.NET to generate HTML, or you can use a more advanced reporting solution such as SQL Reporting Services to generate PDF documents on the fly. The drawback of using server side generated reports for printing is that the user has to click a separate print button in your application to bring up the report. If the user simply clicks the print button in the browser toolbar they will get whatever HTML is available in the browser. This breaks the default user interaction models and is something we should try to avoid if possible. You’re also depending on server side resources to generate the report instead of leveraging the power of the client computer.

Client side printing simply means using the built-in functionality of the browser to provide printing in your application. For most content-centric sites, like blogs and news papers, this is the most obvious solution as the entire HTML is already available in the browser. However, you probably don’t want to print things like navigation elements or large header graphics. To solve this all modern browsers supports separate CSS style sheets for print. This enables the developer or designer to customize the look and feel of the page when printed. You can use CSS to hide navigation elements, large graphics, or other parts of the page you don’t want to include in your printout. This is great for HTML pages, but how does this apply to Silverlight 2 applications?

Silverlight is embedded onto the page using an object-tag, normally sitting inside some div-container. This allows us to apply CSS styles against the Silverlight container. In our CSS print style sheet we simply set the visibility to none to hide the Silverlight content when printing the page. At the same time we can change the visibility of another div-container that was hidden in the screen style sheet, but is now visible when printing the page. This enables us to swap visibility between the Silverlight application and other HTML content sitting behind it. Now we just need to populate this HTML element with meaningful content when printing. The way you interact between Silverlight 2 and the browser is through the HTML Bridge. The HTML Bridge lets you invoke JavaScript functions or manipulate the HTML-DOM from managed code in Silverlight 2. Using this API we can dynamically generate HTML on the client to populate the print div-container. The visibility and style of the printout is controlled by the print style sheet. The next question is how to best generate HTML from Silverlight 2. You have a couple of options;

  • Concatenate strings using the StringBuilder
    The perhaps most straight forward approach would be to write code that builds up a big HTML string in Silverlight 2, and then set the InnerHtml property of the container using the HTML Bridge. This would work just fine, but string concatenation is hard to maintain and easily leads to spaghetti code.
  • Use LINQ to XML to generate HTML
    In many cases this would be a good option as you could easily write LINQ queries against your objects, and then use LINQ to XML to dynamically build up the HTML document. This would be cleaner and easier to test and maintain than concatenating strings. The problem with generating the printout through code is that the look and feel of the printout is part of the user experience, and something that should be owned by the UX team and not the developers. Having to change LINQ to XML code to update report is not very flexible or designer friendly.
  • Use Client-side HTML controls for Silverlight 2
    Jeff Wilcox, the guy behind the Silverlight 2 Testing Frameworks, wrote an interesting post a few days back about a Client-side HTML controls library for Silverlight 2. This is something Jeff wrote for the testing framework to generate the test-report. He had the same problem of dynamically generating HTML from Silverlight, and solved it by implementing an abstraction layer on top of the HTML Bridge to build a client-side HTML control library. The library is built by extending the HtmlElement class to build higher level elements like Button, TextBox, Div, Headings, and even complex controls like a progress bar. This gives you an ASP.NET-like programming model running on the client. You can write clean, testable code against the controls, but you still have to build your reports through code. This makes things hard for your designers. The controls are currently only available through the testing framework, something that could make it hard to use in a production environment. But Jeff definitely got some interesting ideas around creating HTML content on the client that is well worth checking out.
  • ASP.NET AJAX 4.0 Client Templates
    An new and really interesting way of generating HTML on the client is using the new Client Templates introduced in the ASP.NET AJAX 4.0 preview release. The client templates let you define HTML fragments containing JavaScript binding expressions. The templates can later be applied to a JavaScript array to generate HTML on the client. This allows you to keep the HTML outside of your Silverlight code, and the only thing you have to pass over the HTML Bridge is the objects you want to use for your printout. This gives your designers the flexibility to work on the HTML and CSS for the printout while keeping your Silverlight 2 code nice and tidy. This is the approach I’ve taken for adding print support to the Dive Log example application.

Printing using ASP.NET AJAX 4.0 Client Templates

One of the really interesting features of the ASP.NET AJAX 4.0 preview is client templates. This enables you to write HTML fragments containing JavaScript binding expressions. The templates can be applied to JavaScript arrays to generate HTML on the client. I would recommend checking out Bertrand Le Roy’s two part blog post for a good introduction to client templates. Scott Hanselman also did a post showing how to use client templates together with jQuery to build dynamic HTML in an AJAX application. The October issue of MSDN Magazine also got a good article about new AJAX support for data driven web sites. The ASP.NET AJAX 4.0 is preview technology and things are likely to change. However the client template script is just a 50KB JavaScript file so using it shouldn’t make a big impact on your application.

The printing user experience I want to achieve for the Dive Log application is really simple. I don’t want to add a print button to the Silverlight 2 interface. Instead all printing should be done through whatever functionality is available in the browser. Most likely by clicking the print-button in the toolbar, or going to the file menu and selecting print or print preview. The printout shouldn’t contain the Silverlight 2 user interface. Instead it should contain a HTML table listing all logged dives.

The first thing we need to do is include two CSS style sheets, one for print and one for screen. The style sheets are responsible for toggling between showing/hiding the Silverlight 2 container and the print container.

Seperate style sheets for print and screen.

I use the ASP.NET Silverlight Control to render the HTML needed to show the Silverlight 2 application. Underneath the Silverlight control I have a separate HTML-div that will be the container for the dynamically generate print HTML.

Silverlight 2 container

The most interesting part of the print implementation is the client template used to generate the HTML. The meat of the template is a plain HTML table with columns for each of the fields we want to use from the dive log. The body of the table is marked with a special CSS class to indicate that this is a template, and the columns contain JavaScript binding expressions.

ASP.NET AJAX 4 Client Template

To populate the template with data we need some JavaScript. The script is kept in a separate file to keep things nice and clean. The script is responsible for instantiating the template based on the HTML markup. The script also registers a custom markup extension for the format expression used to bind the date column. This shows some of the power of using JavaScript binding expressions, and the extensibility of the client template framework. The final piece of JavaScript is a simple function to bind data against the template. The data is passed in as a JSON string from the Silverlight 2 application, and is de-serialized before the template is applied to the JavaScript array.

JavaScript to populate Client Template (available in seperate download)

The final piece of code needed is the Silverlight 2 code responsible for updating the print template with data. This is done by simply invoking the updatePrint-function passing in a list of Dive object serialized as JSON. The code is added to the View Model and is executed every time Dive Logs are retrieved from the server. The list of dives is serialized to JSON using a simple extensions method.

Using the HTML Bridge to update the print container.

When we run the application and click the print-preview button we no longer get a stretched Silverlight 2 user interface. Instead we get a nice HTML table listing all our logged dives. Since we’re using standard HTML and CSS to do printing it now works in all browsers, and not just IE7 which is the only one currently supporting printing of Silverlight 2 content.

Print preview with custom HTML instead of Silverlight 2 content.

Summary

Printing support is a key feature of most line of business application. Unfortunately this isn’t one of the strong sides of Silverlight 2. Hopefully this will improve in future versions of Silverlight. Microsoft hasn’t made any announcements, but I hope for better support for rich text and text layouts. WPF already has great support for documents, and hopefully some of these features will make it into Silverlight. But for now we have to use existing web technologies to solve printing.

In many cases server side generated report will be a good option. Using the HTML Bridge you can easily bring up a pop-up window where you pass in URL parameters to render the report. However, in some cases you should consider providing a good client side printing experience. Hopefully this blog post have given you some ideas to how to implement printing in Silverlight, and at the same shown some of the power of combining Silverlight with existing AJAX technologies. I did run into some minor challenges using this approach. One of them was figuring out when to update the print section with new HTML. Internet Explorer has a onbeforeprint-event you can listen to, but that one is not available in any other browser. Another option would be to listen to mouseout-events to try to detect when the user is moving up to the toolbar (and potentially could be clicking the print button). Non of these techniques where reliable enough, so I decided to simply update the content every time it’s persisted/loaded from the server. This could lead to some inconsistence if the user edits a dive and click print before saving it back to the server. How you deal with this would depend on your application and requirements.

One added benefit to this approach is that you could render the initial HTML content of the print container on the server using ASP.NET. This would give search engines like Google something to index, making your Silverlight 2 application searchable. The search engines wouldn’t execute your Silverlight or JavaScript code, so this would only work for the initial rendering of the page.

I will post the updated version of the Dive Log application and source code tomorrow when Microsoft, according to rumors, will be releasing Silverlight 2.

blog comments powered by Disqus