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:
这是我的Paginator类:
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.
很抱歉代码转储,但我不想错过相关的东西。
6 个解决方案
#1
17
So I got it working after reading Pro WPF in C# 2008 (Page 726).
所以我在C#2008(页726)中阅读Pro WPF之后就开始工作了。
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(Namespace 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; }
}
#2
5
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中删除包。
#3
3
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 DocumentPage
objects. 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 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.
你最终要做的是,对整个文档进行分页,收集所有的DocumentPage对象,然后在滚动的StackPanel或类似内容中显示它们的视觉效果。这些是您可以发送到打印机的相同DocumentPage对象。
#4
1
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.
P.s。:原始海报评论说这是WPF应用程序的错误答案。
#5
1
XpsDocument doc = new XpsDocument("filename.xps", FileAccess.Read);
docViewer.Document = doc.GetFixedDocumentSequence();
doc.Close();
#6
0
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.xaml http://code.google.com/p/nhaml/source/browse/trunk/src/NHaml.Xps/DocumentDialog.xaml.cs
其中“load”是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.
希望它适用于您的情况。
#1
17
So I got it working after reading Pro WPF in C# 2008 (Page 726).
所以我在C#2008(页726)中阅读Pro WPF之后就开始工作了。
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(Namespace 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; }
}
#2
5
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中删除包。
#3
3
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 DocumentPage
objects. 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 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.
你最终要做的是,对整个文档进行分页,收集所有的DocumentPage对象,然后在滚动的StackPanel或类似内容中显示它们的视觉效果。这些是您可以发送到打印机的相同DocumentPage对象。
#4
1
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.
P.s。:原始海报评论说这是WPF应用程序的错误答案。
#5
1
XpsDocument doc = new XpsDocument("filename.xps", FileAccess.Read);
docViewer.Document = doc.GetFixedDocumentSequence();
doc.Close();
#6
0
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.xaml http://code.google.com/p/nhaml/source/browse/trunk/src/NHaml.Xps/DocumentDialog.xaml.cs
其中“load”是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.
希望它适用于您的情况。