C# 使用 DocumentPaginator 打印时如何打印预览?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/584551/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 09:13:48  来源:igfitidea点击:

How to Print Preview when using a DocumentPaginator to print?

c#.netwpfprinting

提问by Ray

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.

我正在使用从 DocumentPaginator 派生的类(见下文)从 WPF 应用程序打印简单(纯文本)报告。我已经有了它,所以一切都可以正确打印,但是如何在打印前进行打印预览?我有一种感觉,我需要使用 DocumentViewer,但我不知道如何使用。

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).

PageElementRenderer 只是一个简单的 UserControl,用于显示数据(目前只是一个行列表)。

Here's how I use my Row Paginator

这是我如何使用我的 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.

抱歉代码转储,但我不想错过相关的东西。

采纳答案by Ray

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

因此,在阅读了 C# 2008 中的 Pro WPF(第 726 页)后,我开始使用它。

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

基本上 DocumentViewer 类需要一个 XPS 文件来显示它的打印预览。所以我执行以下操作:

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);

我正在创建打印对话框以获取默认页面大小。可能有更好的方法来做到这一点。XpsDocument 位于 ReachFramework.dll(命名空间 System.Windows.Xps.Packaging)中;

Here's the PrintPreview Window.

这是 PrintPreview 窗口。

<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:

后面的代码只有一个 Document 属性,如下所示:

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

回答by MrValdez

The WinForm code for print preview is:

打印预览的 WinForm 代码是:

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

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

Ps:原发帖人评论说这是WPF应用程序的错误答案。

回答by Simon

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

我不认为有一种内置的方式来做到这一点

Here is how I got it working in NHaml

这是我在 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.xamlhttp://code.google.com/p/nhaml/source/browse/trunk/src/NHaml.Xps/DocumentDialog.xaml.cs

其中“加载”是 FlowDocument 或 IDocumentPaginatorSource,这里是 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.

希望它适用于您的情况。

回答by Fortes

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.

WPF 没有任何内置的打印预览功能,如果你想进行打印预览,你将不得不自己构建它。幸运的是,这应该不是那么困难。

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

您已经获得了用于创建DocumentPage对象的分页代码。这些对象包含一个Visual,您可以继续并在您的 UI 中显示它。

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

您最终要做的是对整个文档进行分页,收集所有DocumentPage对象,然后在滚动StackPanel或类似内容中显示它们的视觉效果。这些是DocumentPage您随后可以发送到打印机的相同对象。

回答by Bobsum

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

以下代码使用 MemoryStream 进行打印预览。

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.

请记住在关闭打印预览时使用 close() 并从 PackageStore 中删除包。

回答by pnb

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