开发者

Guidance for Printing Controls bound to data in WPF

I have a requirement for printing controls bound to data in WPF, i will have a user control which will have controls like Grid bound to data and i would like to print the user control. I also need support for Pa开发者_开发问答gination, header and footer and inserting custom logos.

Is there any article/sample code that will help me in getting started.


While it's very simple to send a visual to the printer, it can get a little more involved if you need to handle paging, scaling, headers, and footers. But even this is not all that difficult, and you can generate the printed output by composing user xaml user controls. I like this printing overview on MSDN for a general picture of the workflow.

To do the pagination, you'll want to create a class that inherits from System.Windows.Documents.DocumentPaginator. This class lets you tell the printer what pages to print and how the items are arranged on each page.

Inside the paginator, you'll programatically construct your pages by instantiating the user controls that you want to print. If you want a header / footer, then create user controls for these, instantiate them, set any needed DataContext properties, and add them to your page. In most cases, you can programatically create something like a Grid, configure the columns / rows, add user controls to it, and then return that as a visual.

One trick... you may need to force the layout system to layout the controls. This is done automatically when you show it on the screen, but if you're creating things manually, you'll need to do this yourself:

        var pageSize = new Size(8.5 * 96.0, 11.0 * 96.0);
        var pageRect = new Rect(new Point(0, 0), pageSize);
        ...
        // create root visual (like a grid) and add user controls
        ...
        root.Measure(pageSize);
        root.Arrange(pageRect);
        root.InvalidateVisual();
        root.UpdateLayout();

The documentation on the DocumentPaginator explains how to use the class pretty well. But for the case of paging the data, you'll probably need to do that yourself. I typically determine the size of the page and how many rows I can fit on that page. Then I programatically split the data into multiple sets. Maybe something like 25 items in each collection. Then I bind one set to each page's list / grid.

Lastly, you'll need to get this to the printer. Here's roughly what I use to create an XPS document and send it to the printer. And... You can use a variation of this to easily show a print preview dialog. Just create a dialog that hosts a FixedDocumentViewer that displays the XPS document.

public static string Print(DocumentPaginator paginator, string printQueueName, string documentName)
{
    using (MemoryStream xpsStream = new MemoryStream())
    {
        using (Package package = Package.Open(xpsStream, FileMode.Create, FileAccess.ReadWrite))
        {
            string packageUriString = "memorystream://data.xps";
            Uri packageUri = new Uri(packageUriString);

            try
            {
                PackageStore.AddPackage(packageUri, package);

                using (XpsDocument xpsDocument = new XpsDocument(package, CompressionOption.Maximum, packageUriString))
                {
                    PrintTicket printTicket = new PrintTicket();
                    printTicket.PageMediaSize = new PageMediaSize(paginator.PageSize.Width, paginator.PageSize.Height);

                    var writer = XpsDocument.CreateXpsDocumentWriter(xpsDocument);
                    writer.Write(paginator, printTicket);

                    FixedDocumentSequence document = xpsDocument.GetFixedDocumentSequence();

                    xpsDocument.Close();

                    PrintQueue targetQueue = null;

                    // Get the queue.
                    if (!string.IsNullOrEmpty(printQueueName))
                    {
                        var printServer = new LocalPrintServer();
                        targetQueue = printServer.GetPrintQueue(printQueueName);
                    }

                    // If no queue, then ask the user for a queue.
                    if (null == targetQueue)
                    {
                        var printDialog = new PrintDialog();
                        printDialog.PrintTicket = printTicket;
                        printDialog.UserPageRangeEnabled = false;
                        var response = printDialog.ShowDialog();

                        if (response.GetValueOrDefault() && null != printDialog.PrintQueue)
                        {
                            targetQueue = printDialog.PrintQueue;
                        }
                        else
                        {
                            return null;
                        }
                    }

                    var targetQueueWriter = PrintQueue.CreateXpsDocumentWriter(targetQueue);

                    document.Name = documentName;
                    targetQueueWriter.Write(document);
                    return document.Name;
                }
            }
            finally
            {
                PackageStore.RemovePackage(packageUri);
            }
        }
    }
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜