简体   繁体   中英

How to Print Preview when using a DocumentPaginator to print?

I'm using a class I've derived from DocumentPaginator (see below) to print simple (text only) reports from a WPF application. I've got it so that everything prints correctly, But how do I get it to do a print preview before printing? I have a feeling I need to use a DocumentViewer but I can't figure out how.

Here's my Paginator Class:

public class RowPaginator : DocumentPaginator
{
    private int rows;
    private Size pageSize;
    private int rowsPerPage;

    public RowPaginator(int rows)
    {
        this.rows = rows;
    }

    public override DocumentPage GetPage(int pageNumber)
    {
        int currentRow = rowsPerPage * pageNumber;
        int rowsToPrint = Math.Min(rowsPerPage, rows - (rowsPerPage * pageNumber - 1));
        var page = new PageElementRenderer(pageNumber + 1, PageCount, currentRow, rowsToPrint)
                       {
                           Width = PageSize.Width,
                           Height = PageSize.Height
                       };
        page.Measure(PageSize);
        page.Arrange(new Rect(new Point(0, 0), PageSize));
        return new DocumentPage(page);
    }

    public override bool IsPageCountValid { get { return true; } }

    public override int PageCount { get { return (int)Math.Ceiling(this.rows / (double)this.rowsPerPage); } }

    public override Size PageSize
    {
        get { return this.pageSize; }
        set
        {
            this.pageSize = value;
            this.rowsPerPage = PageElementRenderer.RowsPerPage(this.pageSize.Height);
            if (rowsPerPage <= 0)
                throw new InvalidOperationException("Page can't fit any rows!");
        }
    }

    public override IDocumentPaginatorSource Source { get { return null; } }
}

The PageElementRenderer is just a simple UserControl that displays the data (at the moment just a list of rows).

Here's how I use my Row Paginator

PrintDialog dialog = new PrintDialog();
if (dialog.ShowDialog() == true)
{
    var paginator = new RowPaginator(rowsToPrint) { PageSize = new Size(dialog.PrintableAreaWidth, dialog.PrintableAreaHeight) };

    dialog.PrintDocument(paginator, "Rows Document");
}

Sorry for the code dump, but I didn't want to miss something relevant.

So I got it working after reading Pro WPF in C# 2008 (Page 726).

Basically the DocumentViewer class needs an XPS file to present a print preview of it. So I do the following:

PrintDialog dialog = new PrintDialog();
var paginator = new RowPaginator(rowsToPrint) { PageSize = new Size(dialog.PrintableAreaWidth, dialog.PrintableAreaHeight) };

string tempFileName = System.IO.Path.GetTempFileName();

//GetTempFileName creates a file, the XpsDocument throws an exception if the file already
//exists, so delete it. Possible race condition if someone else calls GetTempFileName
File.Delete(tempFileName); 
using (XpsDocument xpsDocument = new XpsDocument(tempFileName, FileAccess.ReadWrite))
{
    XpsDocumentWriter writer = XpsDocument.CreateXpsDocumentWriter(xpsDocument);
    writer.Write(paginator);

    PrintPreview previewWindow = new PrintPreview
                                     {
                                         Owner = this,
                                         Document = xpsDocument.GetFixedDocumentSequence()
                                     };
    previewWindow.ShowDialog();
}

I'm creating the print dialog to get the default page size. There's probably a better way to do this. XpsDocument is in ReachFramework.dll (Namespace System.Windows.Xps.Packaging);

Here's the PrintPreview Window.

<Window x:Class="WPFPrintTest.PrintPreview"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Name="previewWindow"
    Title="PrintPreview" Height="800" Width="800">
    <Grid>
        <DocumentViewer Name="viewer" 
                        Document="{Binding ElementName=previewWindow, Path=Document}" />
    </Grid>
</Window>

The code behind just has a Document property like so:

public IDocumentPaginatorSource Document
{
    get { return viewer.Document; }
    set { viewer.Document = value; }
}

The following code uses a MemoryStream to do a print preview.

MemoryStream stream = new MemoryStream();

Package package = Package.Open(stream, FileMode.Create, FileAccess.ReadWrite);

var uri = new Uri(@"memorystream://myXps.xps");
PackageStore.AddPackage(uri, package);
var xpsDoc = new XpsDocument(package);

xpsDoc.Uri = uri;
XpsDocument.CreateXpsDocumentWriter(xpsDoc).Write(paginator);

documentViewer.Document = xpsDoc.GetFixedDocumentSequence();

Remember to use close() and remove package from PackageStore when the print preview is closed.

WPF doesn't come with any built-in Print Preview functionality, if you want to do a print preview, you're going to have to construct it yourself. Fortunately, it's shouldn't be that difficult.

You've already got the pagination code, which creates your DocumentPage objects. These objects contain a Visual , which you can go ahead and display in your UI.

What you'll end up doing, is paginating your entire document, collecting all the DocumentPage objects, then displaying their visuals inside of a scrolling StackPanel or something similar. These are the same DocumentPage objects that you can then send to the printer.

The WinForm code for print preview is:

PrintPreviewDialog PrintPreviewDialog = new PrintPreviewDialog();
PrintPreviewDialog.Document = PrintDocument;
PrintPreviewDialog.ShowDialog();

Ps: The original poster has commented that this is the wrong answer for an WPF application.

XpsDocument doc = new XpsDocument("filename.xps", FileAccess.Read);
docViewer.Document = doc.GetFixedDocumentSequence();
doc.Close();

I dont think there is a built in way of doing this

Here is how I got it working in NHaml

var documentViewHostDialog = new DocumentDialog();
documentViewHostDialog.LoadDocument(load);
documentViewHostDialog.ShowDialog();

Where "load" is either a FlowDocument or IDocumentPaginatorSource and here is the DocumentDialog http://code.google.com/p/nhaml/source/browse/trunk/src/NHaml.Xps/DocumentDialog.xaml http://code.google.com/p/nhaml/source/browse/trunk/src/NHaml.Xps/DocumentDialog.xaml.cs

Hope it works for your case.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM