skink
skink

Reputation: 5736

Printing on a paper form with preview

We've got a large stock of paper forms that we need to fill out. It's very tedious to do this by hand, so we're building an application. It should provide a form to fill in data, be able to show print preview, print the data on the paper form, and keep the history.

Currently, we have a FixedPage which we print like this:

var dlg = new PrintDialog();
if (dlg.ShowDialog() == true)
{
    var doc = new FixedDocument();
    doc.DocumentPaginator.PageSize = new Size(11.69 * 96, 8.27 * 96); // A4 Landscape

    var fp = Application.LoadComponent(new Uri("/FixedPage.xaml", UriKind.Relative)) as FixedPage;
    fp.DataContext = this;
    fp.UpdateLayout();

    var pc = new PageContent();
    ((IAddChild)pc).AddChild(fp);
    doc.Pages.Add(pc);

    dlg.PrintTicket.PageOrientation = System.Printing.PageOrientation.Landscape;
    dlg.PrintDocument(doc.DocumentPaginator, string.Format("Form #{0}", FormNumber));
}

For the print preview we have a custom UserControl with scanned image of the paper form on background and the data on foreground. Basically, it's repeating the FixedPage layout, and all this makes us think there's a flaw in our design.

Is there a better way to do what we want?

Upvotes: 3

Views: 1036

Answers (2)

skink
skink

Reputation: 5736

We have managed to find a solution, which allows us to throw away a bunch of renundant code. It is still ugly:

public class CustomDocumentViewer : DocumentViewer
{
    public static readonly DependencyProperty BackgroundImageProperty =
        DependencyProperty.Register("BackgroundImage", typeof(Image), typeof(CustomDocumentViewer), new UIPropertyMetadata(null));

    public Image BackgroundImage
    {
        get { return GetValue(BackgroundImageProperty) as Image; }
        set { SetValue(BackgroundImageProperty, value); }
    }

    protected override void OnDocumentChanged()
    {
        (Document as FixedDocument).Pages[0].Child.Children.Insert(0, BackgroundImage);
        base.OnDocumentChanged();
    }

    protected override void OnPrintCommand()
    {
        var printDialog = new PrintDialog();
        if (printDialog.ShowDialog() == true)
        {
            (Document as FixedDocument).Pages[0].Child.Children.RemoveAt(0);
            printDialog.PrintDocument(Document.DocumentPaginator, "Test page");
            (Document as FixedDocument).Pages[0].Child.Children.Insert(0, BackgroundImage);
        }
    }
}

...

<local:CustomDocumentViewer x:Name="viewer" BackgroundImage="{StaticResource PaperFormImage}"/>

...

InitializeComponent();
viewer.Document = Application.LoadComponent(new Uri("/PaperFormDocument.xaml", UriKind.Relative)) as IDocumentPaginatorSource;

The reason why we're using Application.LoadComponent instead of binding is a five years old bug: http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=293646

Upvotes: 1

tylerjgarland
tylerjgarland

Reputation: 643

I was tasked with the same problem and wanted to avoid writing my own templating system to save time, unit testing, and my sanity.

I ended up writing a hybrid to did some cool things. First, I wrote my templates using HTML and CSS. It was very easy to do and allowed for great flexibility when making minor adjustments from our Marketing department.

I filled the template with my own tags (e.g [code_type/], [day_list]...[/day_list]) and string replaced the text with a dictionary of tags that could be a single or multivalued.

After generating the html, I would use an html to pdf library I found that uses the open-source webkit engine to render and create the generated pdf. It turned out very stable and took around 2 weeks to write the initial program. Everyone was very pleased and testing was a breeze.

If you want more details, send me a message or reply to this.

Upvotes: 2

Related Questions