Simple ReportDocument for Silverlight 4

By Fons Sonnemans, 25-11-2009

I have written an Simple Report Library for Windows Forms applications a few years ago. The new Printing API makes it possible to create a similar solution for Silverlight 4.

You create a report by instantiating a new ReportDocument object. You can set the Title and the SubTitle. Next you add Paragraphs (FrameworkElements) to the report. Finally you Print the report.

ReportDocument r = new ReportDocument() {

    Title = "Test Title",

    SubTitle = "Test SubTitle",

};


for (int i = 0; i < 40; i++) {


    var tb = new TextBlock() {

        Text = "Test text " + i,

        FontSize = i + 10,

    };


    r.Paragraphs.Add(tb);

}


r.Print();

This prints the following Test Title.pdf if you print it to a PDF writer.

Test Title.pdf

The real magic is in the dp_PrintPage event handler of the ReportDocument class. The Header and the Paragraphs are added to a StackPanel. Before a paragraph is added the height (actual or the measured desired) is compared with the available space. If it doesn't fit the page is full and ready to be printed. The PageVisual is set to the StackPanel. The next page will continue with the current paragraph.

private void pd_PrintPage(object sender, PrintPageEventArgs e) {

    PageNumber++;

    if (_panel.Children.Count == 0) {

        _panel.Children.Add(Header);

    } else {

        // remove all except header

        while (_panel.Children.Count > 1) {

            _panel.Children.RemoveAt(1);

        }

    }

    _visual.Height = e.PrintableArea.Height;

    _visual.Width = e.PrintableArea.Width;


    double totalHeight = e.PrintableArea.Height - this.Margin.Top - this.Margin.Bottom;

    double totalWidth = e.PrintableArea.Width - this.Margin.Left - this.Margin.Right;


    double height;

    if (_header.ActualHeight > 0) {

        height = Header.ActualHeight;

    } else {

        Header.Measure(new Size(totalWidth, totalHeight));

        height = Header.DesiredSize.Height;

    }


    while (_currentParagraphIndex < Paragraphs.Count) {

        var paragraph = Paragraphs[_currentParagraphIndex];

        if (paragraph.ActualHeight > 0) {

            height += paragraph.ActualHeight;

        } else {

            var size = new Size(totalWidth, totalHeight - height);

            paragraph.Measure(size);

            height += paragraph.DesiredSize.Height;

        }

        if (height > totalHeight) {

            // doesn't fit anymore

            break;

        }

        _currentParagraphIndex++;

        _panel.Children.Add(paragraph);

    }


    e.PageVisual = _visual;

    e.HasMorePages = _currentParagraphIndex < Paragraphs.Count;

}

I hope you like it. I will discuss creating custom headers in a next post. You can download the code from Codeplex.

Leave a Comment

Leave a Comment
Name
Comment
4 + 4 =

0 Comments

All postings/content on this blog are provided "AS IS" with no warranties, and confer no rights. All entries in this blog are my opinion and don't necessarily reflect the opinion of my employer or sponsors. The content on this site is licensed under a Creative Commons Attribution By license.