WPF 的打印对话框和打印预览对话框
Print dialog and print prewiew dialog for WPF
是否有 WPF 的打印对话框与 WPF 中的打印预览对话框相结合,例如 Google Chrome 或 Word?
此时我使用 Windows 表单中的打印预览对话框。我也尝试使用它的 WPF 版本。但是WPF没有PrintPreviewDialog
或者PrintPrewiewControl
。这是我的代码:
//To the top of my class file:
using Forms = System.Windows.Forms;
//in a methode on the same class:
PageSettings setting = new PageSettings();
setting.Landscape = true;
_document = new PrintDocument();
_document.PrintPage += _document_PrintPage;
_document.DefaultPageSettings = setting ;
Forms.PrintPreviewDialog printDlg = new Forms.PrintPreviewDialog();
printDlg.Document = _document;
printDlg.Height = 500;
printDlg.Width = 200;
try
{
if (printDlg.ShowDialog() == Forms.DialogResult.OK)
{
_document.Print();
}
}
catch (InvalidPrinterException)
{
MessageBox.Show("No printers found.", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
}
我也搜索了 NuGet 包,但没有找到真正好的。
您的要求可以通过多种方式实现,例如,您可以
使用 PrintDialog
class。以下 MSDN 页面包含说明以及一些示例代码:
- WinForms:System.Windows.Forms.PrintDialog
- WPF: System.Windows.Controls.PrintDialog (thanks to Bartosz)
也可以通过 C# 实现,例如,考虑下一个代码:
private string _previewWindowXaml =
@"<Window
xmlns ='http://schemas.microsoft.com/netfx/2007/xaml/presentation'
xmlns:x ='http://schemas.microsoft.com/winfx/2006/xaml'
Title ='Print Preview - @@TITLE'
Height ='200' Width ='300'
WindowStartupLocation ='CenterOwner'>
<DocumentViewer Name='dv1'/>
</Window>";
internal void DoPreview(string title)
{
string fileName = System.IO.Path.GetRandomFileName();
FlowDocumentScrollViewer visual = (FlowDocumentScrollViewer)(_parent.FindName("fdsv1"));
try
{
// write the XPS document
using (XpsDocument doc = new XpsDocument(fileName, FileAccess.ReadWrite))
{
XpsDocumentWriter writer = XpsDocument.CreateXpsDocumentWriter(doc);
writer.Write(visual);
}
// Read the XPS document into a dynamically generated
// preview Window
using (XpsDocument doc = new XpsDocument(fileName, FileAccess.Read))
{
FixedDocumentSequence fds = doc.GetFixedDocumentSequence();
string s = _previewWindowXaml;
s = s.Replace("@@TITLE", title.Replace("'", "'"));
using (var reader = new System.Xml.XmlTextReader(new StringReader(s)))
{
Window preview = System.Windows.Markup.XamlReader.Load(reader) as Window;
DocumentViewer dv1 = LogicalTreeHelper.FindLogicalNode(preview, "dv1") as DocumentViewer;
dv1.Document = fds as IDocumentPaginatorSource;
preview.ShowDialog();
}
}
}
finally
{
if (File.Exists(fileName))
{
try
{
File.Delete(fileName);
}
catch
{
}
}
}
}
它的作用:它实际上将视觉内容打印到 XPS 文档中。然后它加载“打印的”XPS 文档并将其显示在一个非常简单的 XAML 文件中,该文件存储为字符串,而不是单独的模块,并在运行时动态加载。生成的 Window 具有 DocumentViewer 按钮:打印、调整到最大页面宽度等。
我还添加了一些代码来隐藏搜索框。请参阅 this answer to WPF: How can I remove the searchbox in a DocumentViewer? 了解我是如何做到的。
效果是这样的:
XpsDocument 可以在 ReachFramework dll 中找到,XpsDocumentWriter 可以在 System.Printing dll 中找到,两者都必须添加为对项目的引用
您想要做的,是从您要打印的内容(flowDocument
)中创建一个 xpsDocument
并使用该 XpsDocument
来预览内容,因为例如,假设您有以下 Xaml,您想要打印其内容的 flowDocument
:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<FlowDocumentScrollViewer>
<FlowDocument x:Name="FD">
<Paragraph>
<Image Source="http://www.wpf-tutorial.com/images/logo.png" Width="90" Height="90" Margin="0,0,30,0" />
<Run FontSize="120">WPF</Run>
</Paragraph>
<Paragraph>
WPF, which stands for
<Bold>Windows Presentation Foundation</Bold> ,
is Microsoft's latest approach to a GUI framework, used with the .NET framework.
Some advantages include:
</Paragraph>
<List>
<ListItem>
<Paragraph>
It's newer and thereby more in tune with current standards
</Paragraph>
</ListItem>
<ListItem>
<Paragraph>
Microsoft is using it for a lot of new applications, e.g. Visual Studio
</Paragraph>
</ListItem>
<ListItem>
<Paragraph>
It's more flexible, so you can do more things without having to write or buy new controls
</Paragraph>
</ListItem>
</List>
</FlowDocument>
</FlowDocumentScrollViewer>
<Button Content="Print" Grid.Row="1" Click="Button_Click"></Button>
</Grid>
flowDocument 示例来自 Wpf tutorials site
打印按钮的 Click 事件处理程序应如下所示:
private void Button_Click(object sender, RoutedEventArgs e)
{
if (File.Exists("printPreview.xps"))
{
File.Delete("printPreview.xps");
}
var xpsDocument = new XpsDocument("printPreview.xps", FileAccess.ReadWrite);
XpsDocumentWriter writer = XpsDocument.CreateXpsDocumentWriter(xpsDocument);
writer.Write(((IDocumentPaginatorSource)FD).DocumentPaginator);
Document = xpsDocument.GetFixedDocumentSequence();
xpsDocument.Close();
var windows = new PrintWindow(Document);
windows.ShowDialog();
}
public FixedDocumentSequence Document { get; set; }
所以你主要是:
- 正在创建 Xps 文档并将其存储在 printPreview.xps 文件中,
- 正在将
FlowDocument
内容写入该文件,
- 将
XpsDocument
传递给 PrintWindow
处理预览和打印操作,
此处 PrintWindow
的样子:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="1.5*"/>
</Grid.ColumnDefinitions>
<StackPanel>
<Button Content="Print" Click="Button_Click"></Button>
<!--Other print operations-->
</StackPanel>
<DocumentViewer Grid.Column="1" x:Name="PreviewD">
</DocumentViewer>
</Grid>
和后面的代码:
public partial class PrintWindow : Window
{
private FixedDocumentSequence _document;
public PrintWindow(FixedDocumentSequence document)
{
_document = document;
InitializeComponent();
PreviewD.Document =document;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
//print directly from the Xps file
}
}
最终结果看起来像这样
Ps:要使用 XpsDocument,您应该添加对 System.Windows.Xps.Packaging namespace
的引用
这是打印预览的示例解决方案:
MainWindow.xaml
<FlowDocumentScrollViewer>
<FlowDocument x:Name="FD">
<Paragraph>
<Run FontSize="120">WPF</Run>
</Paragraph>
<Paragraph>
WPF, which stands for
<Bold>Windows Presentation Foundation</Bold> ,
is Microsoft's latest approach to a GUI framework, used with the .NET framework.
Some advantages include:
</Paragraph>
<List>
<ListItem>
<Paragraph>
It's newer and thereby more in tune with current standards
</Paragraph>
</ListItem>
<ListItem>
<Paragraph>
Microsoft is using it for a lot of new applications, e.g. Visual Studio
</Paragraph>
</ListItem>
<ListItem>
<Paragraph>
It's more flexible, so you can do more things without having to write or buy new controls
</Paragraph>
</ListItem>
</List>
</FlowDocument>
</FlowDocumentScrollViewer>
<Button Content="Print" Click="Button_Click"></Button>
MainWindow.xaml.cs
private void Button_Click(object sender, RoutedEventArgs e)
{
//Fix the size of the document
PrintDialog pd = new PrintDialog();
FD.PageHeight = pd.PrintableAreaHeight;
FD.PageWidth = pd.PrintableAreaWidth;
FD.PagePadding = new Thickness(30);
FD.ColumnGap = 0;
FD.ColumnWidth = pd.PrintableAreaWidth;
////to print the document directly without print preview
//IDocumentPaginatorSource dps = FD;
//pd.PrintDocument(dps.DocumentPaginator, "flow doc");
//Print preview the document before printing
if (File.Exists("printPreview.xps")) File.Delete("printPreview.xps");
var xpsDocument = new XpsDocument("printPreview.xps", FileAccess.ReadWrite);
XpsDocumentWriter writer = XpsDocument.CreateXpsDocumentWriter(xpsDocument);
writer.Write(((IDocumentPaginatorSource)FD).DocumentPaginator);
Document = xpsDocument.GetFixedDocumentSequence();
xpsDocument.Close();
var windows = new PrintPreview(Document);
windows.ShowDialog();
}
PrintPreview.xaml
<Window ........>
<DocumentViewer x:Name="PreviewD" />
</Window>
PrintPreview.xaml.cs
public partial class PrintPreview : Window
{
private FixedDocumentSequence _document;
public PrintPreview(FixedDocumentSequence document)
{
_document = document;
InitializeComponent();
PreviewD.Document = document;
}
}
是否有 WPF 的打印对话框与 WPF 中的打印预览对话框相结合,例如 Google Chrome 或 Word?
此时我使用 Windows 表单中的打印预览对话框。我也尝试使用它的 WPF 版本。但是WPF没有PrintPreviewDialog
或者PrintPrewiewControl
。这是我的代码:
//To the top of my class file:
using Forms = System.Windows.Forms;
//in a methode on the same class:
PageSettings setting = new PageSettings();
setting.Landscape = true;
_document = new PrintDocument();
_document.PrintPage += _document_PrintPage;
_document.DefaultPageSettings = setting ;
Forms.PrintPreviewDialog printDlg = new Forms.PrintPreviewDialog();
printDlg.Document = _document;
printDlg.Height = 500;
printDlg.Width = 200;
try
{
if (printDlg.ShowDialog() == Forms.DialogResult.OK)
{
_document.Print();
}
}
catch (InvalidPrinterException)
{
MessageBox.Show("No printers found.", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
}
我也搜索了 NuGet 包,但没有找到真正好的。
您的要求可以通过多种方式实现,例如,您可以
使用 PrintDialog
class。以下 MSDN 页面包含说明以及一些示例代码:
- WinForms:System.Windows.Forms.PrintDialog
- WPF: System.Windows.Controls.PrintDialog (thanks to Bartosz)
也可以通过 C# 实现,例如,考虑下一个代码:
private string _previewWindowXaml =
@"<Window
xmlns ='http://schemas.microsoft.com/netfx/2007/xaml/presentation'
xmlns:x ='http://schemas.microsoft.com/winfx/2006/xaml'
Title ='Print Preview - @@TITLE'
Height ='200' Width ='300'
WindowStartupLocation ='CenterOwner'>
<DocumentViewer Name='dv1'/>
</Window>";
internal void DoPreview(string title)
{
string fileName = System.IO.Path.GetRandomFileName();
FlowDocumentScrollViewer visual = (FlowDocumentScrollViewer)(_parent.FindName("fdsv1"));
try
{
// write the XPS document
using (XpsDocument doc = new XpsDocument(fileName, FileAccess.ReadWrite))
{
XpsDocumentWriter writer = XpsDocument.CreateXpsDocumentWriter(doc);
writer.Write(visual);
}
// Read the XPS document into a dynamically generated
// preview Window
using (XpsDocument doc = new XpsDocument(fileName, FileAccess.Read))
{
FixedDocumentSequence fds = doc.GetFixedDocumentSequence();
string s = _previewWindowXaml;
s = s.Replace("@@TITLE", title.Replace("'", "'"));
using (var reader = new System.Xml.XmlTextReader(new StringReader(s)))
{
Window preview = System.Windows.Markup.XamlReader.Load(reader) as Window;
DocumentViewer dv1 = LogicalTreeHelper.FindLogicalNode(preview, "dv1") as DocumentViewer;
dv1.Document = fds as IDocumentPaginatorSource;
preview.ShowDialog();
}
}
}
finally
{
if (File.Exists(fileName))
{
try
{
File.Delete(fileName);
}
catch
{
}
}
}
}
它的作用:它实际上将视觉内容打印到 XPS 文档中。然后它加载“打印的”XPS 文档并将其显示在一个非常简单的 XAML 文件中,该文件存储为字符串,而不是单独的模块,并在运行时动态加载。生成的 Window 具有 DocumentViewer 按钮:打印、调整到最大页面宽度等。
我还添加了一些代码来隐藏搜索框。请参阅 this answer to WPF: How can I remove the searchbox in a DocumentViewer? 了解我是如何做到的。
效果是这样的:
XpsDocument 可以在 ReachFramework dll 中找到,XpsDocumentWriter 可以在 System.Printing dll 中找到,两者都必须添加为对项目的引用
您想要做的,是从您要打印的内容(flowDocument
)中创建一个 xpsDocument
并使用该 XpsDocument
来预览内容,因为例如,假设您有以下 Xaml,您想要打印其内容的 flowDocument
:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<FlowDocumentScrollViewer>
<FlowDocument x:Name="FD">
<Paragraph>
<Image Source="http://www.wpf-tutorial.com/images/logo.png" Width="90" Height="90" Margin="0,0,30,0" />
<Run FontSize="120">WPF</Run>
</Paragraph>
<Paragraph>
WPF, which stands for
<Bold>Windows Presentation Foundation</Bold> ,
is Microsoft's latest approach to a GUI framework, used with the .NET framework.
Some advantages include:
</Paragraph>
<List>
<ListItem>
<Paragraph>
It's newer and thereby more in tune with current standards
</Paragraph>
</ListItem>
<ListItem>
<Paragraph>
Microsoft is using it for a lot of new applications, e.g. Visual Studio
</Paragraph>
</ListItem>
<ListItem>
<Paragraph>
It's more flexible, so you can do more things without having to write or buy new controls
</Paragraph>
</ListItem>
</List>
</FlowDocument>
</FlowDocumentScrollViewer>
<Button Content="Print" Grid.Row="1" Click="Button_Click"></Button>
</Grid>
flowDocument 示例来自 Wpf tutorials site
打印按钮的 Click 事件处理程序应如下所示:
private void Button_Click(object sender, RoutedEventArgs e)
{
if (File.Exists("printPreview.xps"))
{
File.Delete("printPreview.xps");
}
var xpsDocument = new XpsDocument("printPreview.xps", FileAccess.ReadWrite);
XpsDocumentWriter writer = XpsDocument.CreateXpsDocumentWriter(xpsDocument);
writer.Write(((IDocumentPaginatorSource)FD).DocumentPaginator);
Document = xpsDocument.GetFixedDocumentSequence();
xpsDocument.Close();
var windows = new PrintWindow(Document);
windows.ShowDialog();
}
public FixedDocumentSequence Document { get; set; }
所以你主要是:
- 正在创建 Xps 文档并将其存储在 printPreview.xps 文件中,
- 正在将
FlowDocument
内容写入该文件, - 将
XpsDocument
传递给PrintWindow
处理预览和打印操作,
此处 PrintWindow
的样子:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="1.5*"/>
</Grid.ColumnDefinitions>
<StackPanel>
<Button Content="Print" Click="Button_Click"></Button>
<!--Other print operations-->
</StackPanel>
<DocumentViewer Grid.Column="1" x:Name="PreviewD">
</DocumentViewer>
</Grid>
和后面的代码:
public partial class PrintWindow : Window
{
private FixedDocumentSequence _document;
public PrintWindow(FixedDocumentSequence document)
{
_document = document;
InitializeComponent();
PreviewD.Document =document;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
//print directly from the Xps file
}
}
最终结果看起来像这样
Ps:要使用 XpsDocument,您应该添加对 System.Windows.Xps.Packaging namespace
的引用这是打印预览的示例解决方案: MainWindow.xaml
<FlowDocumentScrollViewer>
<FlowDocument x:Name="FD">
<Paragraph>
<Run FontSize="120">WPF</Run>
</Paragraph>
<Paragraph>
WPF, which stands for
<Bold>Windows Presentation Foundation</Bold> ,
is Microsoft's latest approach to a GUI framework, used with the .NET framework.
Some advantages include:
</Paragraph>
<List>
<ListItem>
<Paragraph>
It's newer and thereby more in tune with current standards
</Paragraph>
</ListItem>
<ListItem>
<Paragraph>
Microsoft is using it for a lot of new applications, e.g. Visual Studio
</Paragraph>
</ListItem>
<ListItem>
<Paragraph>
It's more flexible, so you can do more things without having to write or buy new controls
</Paragraph>
</ListItem>
</List>
</FlowDocument>
</FlowDocumentScrollViewer>
<Button Content="Print" Click="Button_Click"></Button>
MainWindow.xaml.cs
private void Button_Click(object sender, RoutedEventArgs e)
{
//Fix the size of the document
PrintDialog pd = new PrintDialog();
FD.PageHeight = pd.PrintableAreaHeight;
FD.PageWidth = pd.PrintableAreaWidth;
FD.PagePadding = new Thickness(30);
FD.ColumnGap = 0;
FD.ColumnWidth = pd.PrintableAreaWidth;
////to print the document directly without print preview
//IDocumentPaginatorSource dps = FD;
//pd.PrintDocument(dps.DocumentPaginator, "flow doc");
//Print preview the document before printing
if (File.Exists("printPreview.xps")) File.Delete("printPreview.xps");
var xpsDocument = new XpsDocument("printPreview.xps", FileAccess.ReadWrite);
XpsDocumentWriter writer = XpsDocument.CreateXpsDocumentWriter(xpsDocument);
writer.Write(((IDocumentPaginatorSource)FD).DocumentPaginator);
Document = xpsDocument.GetFixedDocumentSequence();
xpsDocument.Close();
var windows = new PrintPreview(Document);
windows.ShowDialog();
}
PrintPreview.xaml
<Window ........>
<DocumentViewer x:Name="PreviewD" />
</Window>
PrintPreview.xaml.cs
public partial class PrintPreview : Window
{
private FixedDocumentSequence _document;
public PrintPreview(FixedDocumentSequence document)
{
_document = document;
InitializeComponent();
PreviewD.Document = document;
}
}