2009-02-25 152 views
13

我正在使用从DocumentPaginator派生的类(请参见下文)从WPF应用程序打印简单(仅文本)报告。我已经知道了所有东西都可以正确打印,但是,如何在打印之前将其打印预览?我有一种感觉,我需要使用DocumentViewer,但我无法弄清楚如何。如何使用DocumentPaginator打印时打印预览?

这里是我的分页程序类:

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

的PageElementRenderer只是一个简单的用户控件来显示数据(目前仅排列表)。

下面是我如何使用我行分页程序

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

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

+0

另见:http://stackoverflow.com/questions/2322064/how-can-i-produce-a-print-preview-of-a-flowdocument-in-a-wpf-application – Cheeso 2010-03-04 19:10:55

回答

17

因此,我在阅读Pro WPF in C# 2008(页726)后才开始工作。

基本上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(); 
} 

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

这里是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> 

后面的代码只是有一个文档属性,像这样:

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

打印预览的WinForm的代码是:

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

P.S:楼主有评论说,这是一个WPF应用程序错误的答案。

+0

这WinForms的做法。 – Ray 2009-02-25 03:58:57

+0

我站好了。 :( – MrValdez 2009-02-25 04:03:51

+0

我希望你不介意,我将这个答案留在这里,以便将来在c#和print上进行搜索。 – MrValdez 2009-02-25 04:07:53

0

我不认为有一个内置在做这个

下面的方法是我得到了它在NHaml

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

工作在哪里“负荷”可以是一个的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

希望它适用于您的情况。

3

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

你已经有了分页代码,它创建了你的DocumentPage对象。这些对象包含一个Visual,您可以继续并在您的用户界面中显示。

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

5

下面的代码使用一个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(); 

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

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