How To: Print your DataGrid (or any UIElement) on multiple pages with Silverlight 4

Friday, January 15, 2010 by Vladimir Enchev | Comments 15

In Silverlight 4 you can use PrintDocument to print easily any UIElement:

   var doc = new PrintDocument();
   doc.DocumentName = YourDocumentName;

   doc.PrintPage += (s, e) =>
   {
        e.PageVisual = YouUIElement;
   };
   doc.Print();


and I’ve made an extension method that can be used to print any UIElement on multiple pages:

public static void Print(this UIElement source, string documentName)
{
    var doc = new PrintDocument();
    doc.DocumentName = documentName;

    var offsetY = 0d;
    var totalHeight = 0d;

    var canvas = new Canvas();
    canvas.Children.Add(source);

    doc.PrintPage += (s, e) =>
    {
        e.PageVisual = canvas;

        if (totalHeight == 0)
        {
            totalHeight = source.DesiredSize.Height;
        }

        Canvas.SetTop(source, -offsetY);

        offsetY += e.PrintableArea.Height;

        e.HasMorePages = offsetY <= totalHeight;
    };

    doc.Print();
}

You can download the attached application (Visual Studio 2010) to check how easily you can print RadGridView for Silverlight on multiple pages.

Enjoy!

15 Comments

  • brownj 04 Mar 2010
    Very handy. Thanks!
  • Jeff 09 Apr 2010
    When I try to implement this I get an error saying source is already a child of another object. Can you help?
  • Vlad 12 Apr 2010
    You may need to clone the UIElement similar to the demo - check the source code.
  • Joe 21 May 2010
    When I open the projec up in VS2010 I get the following errors in the demo project
    'System.Windows.Printing.PrintDocument' does not contain a definition for 'DocumentName'
    'System.Windows.Printing.PrintDocument' does not contain a definition for 'Print'
  • Vlad 25 May 2010
    Here is how to change the Print() method with latest Silverlight 4:

            public static void Print(this UIElement source, string documentName)
            {
                var doc = new PrintDocument();

                var offsetY = 0d;
                var totalHeight = 0d;

                var canvas = new Canvas();
                canvas.Children.Add(source);

                doc.PrintPage += (s, e) =>
                {
                    e.PageVisual = canvas;

                    if (totalHeight == 0)
                    {
                        totalHeight = source.DesiredSize.Height;
                    }

                    Canvas.SetTop(source, -offsetY);

                    offsetY += e.PrintableArea.Height;
                    e.HasMorePages = offsetY <= totalHeight;
                };
                doc.Print(documentName);
            }
  • Alessio 24 Jun 2010
    Hi ,
    when i tried to print a RadChart it doesn't show dataseries.
    Any suggestion?
  • Warren 19 Jul 2010
    Could you post a VB version?  The converters have trouble with doc.PrintPage += (s,e) => ....
  • Warren 19 Jul 2010
    Could you post a VB version?  The converters have trouble with doc.PrintPage += (s,e) => ....
  • Warren 19 Jul 2010
    Could you post a VB version?  The converters have trouble with doc.PrintPage += (s,e) => ....
  • Rodney Foley 08 Nov 2010
    Vlad,

    "You may need to clone the UIElement similar to the demo - check the source code." - Vlad

    There is no cloning being done in your project's source code or any posted on this post.  Your blog post is being used to show people how to print RadChart's but it doesn't work for RadChart's because you can't add it as a child to Canvas because it already is a child to another UIElement.  You response to this was the quote above which doesn't make sense because your source code doesn't do any cloning so checking the source code doesn't do any good.

    Also there is no obvious or easy way to Clone a UIElement.

    It seems to work if you just remove these three lines.
    var canvas = new Canvas(); 
    canvas.Children.Add(source); 
    ... 
    Canvas.SetTop(source, -offsetY); 

    You just then have to work out how to size it to the paper, otherwise it will print to be the size displayed.  This is what adding it to a canvas helps do, but for now this is passable for a RadChart.

    Regardless Telerik should stop referencing this as post as how to print RadChart's when it is only designed to print RadGridView's and doesn't work as is for RadChart's.  I would recommend fixing the demo to actually work with ALL UIElements or fix it so that it will only work with RadGridView on the extension method.
  • Vlad 09 Nov 2010
    Hi,

    You can check the ToPrintFriendlyGrid() static method for more info about the cloning. Here is the code:

            static GridViewDataControl ToPrintFriendlyGrid(this GridViewDataControl source) 
            { 
                var grid = new RadGridView() 
                { 
                    DataContext = source.DataContext, 
                    ItemsSource = source.ItemsSource, 
                    RowIndicatorVisibility = Visibility.Collapsed, 
                    ShowGroupPanel = false
                    CanUserFreezeColumns = false
                    IsFilteringAllowed = false
                    AutoExpandGroups = true
                    AutoGenerateColumns = false 
                }; 
          ...
  • Prince. 10 Jan 2011
    Thanks, this is very simple but hugely useful code snippet.

    Thanks once again for savin my time.
  • RJ 03 May 2012
    I am getting following exception when adding SL4 DataGrid to canvas : - Element is already the child of another element. 
  • RJ 03 May 2012
    I am getting following exception when adding SL4 DataGrid to canvas : - Element is already the child of another element. 
  • RJ 03 May 2012
    I am getting following exception when adding SL4 DataGrid to canvas : - Element is already the child of another element. 

Add comment

  1. Formatting options
       
     
     
     
     
       
  2. (optional, emails won't be shown on public pages)
  3. (optional)