在WPF中实现XPS打印和预览功能

这一生的挚爱 提交于 2020-01-03 04:39:46

     XPS是.net中的一个全新的打印架构,它是一个固定布局的描述格式,不仅它是WPF打印输出的基础,而且还可以把它当做独立的文件格式来使用。于是我们在设计WPF的打印功能时首先不得不想到XPS打印。由于在网上关于WPF设计的XPS打印的介绍不多,而且在MSDN上介绍的XPS打印设计也是基于.net硬编码的方式来完成的,对所见即所得的支持不好。于是笔者根据XPS打印API做了一个自己的基于FixedDocument的打印服务。并调用了内置的DocumentViewer的文档显示服务和打印功能。

一、首先看一下WPF中对XPS提供的三种文档的打印服务:

    1、 打印固定的文档类,包括FixedPage、FixedDocument、FixedDocumentSequence类,这些类提供了用于提交一个单独的页面、一整个文档或者一个含有若干文件的打印。

    2、 打印流式的文档类,主要是FlowDocument类,提供对文档流的打印。

    3、 打印可视元素类,主要是Visual及派生类对象,提供对可视树的打印。

二、接下来我们看一下XPS打印的服务的重要的类:

    1、 XPSDocument:是一个打印包方面的服务文档类,如装载和保存XPS文档或者添加缩微图等。

     public XpsDocument(string path,FileAccess packageAccess)

     用默认的隔行扫描、资源和压缩选项初始化指定的 Package 文件中包含的XpsDocument 类的一个新实例。

     public static XpsDocumentWriter CreateXpsDocumentWriter(XpsDocument xpsDocument)

     创建一个用于编写 XpsDocument 的 XpsDocumentWriter。

     public FixedDocumentSequence GetFixedDocumentSequence()

     返回位于包根位置的固定文档序列。

    2、XPSDocumentWriter:打印操作的基类,用于对打印磁盘的操作及对象树的组织结构。

    void Write()同步向 XPS 文档或打印队列中写入数据。

    void WriteAsync()异步写入已创建 XpsDocumentWriter 的 XpsDocument 或 PrintQueue

三、基本思路:

    为了将打印文档提供给用户并使用WPF内置的打印显示框架,我们使用了WPF的DocumentViewer类提供文档的显示和打印服务。这里实现了两个主要的功能:

无标题

四、具体实现:

  1、 定义一个文件打印的帮助类:

    public class FileHelper{……}

   在这个类中我们实现了两个方法

打开XPS文件
public static string OpenXPSFileFromDialog(){OpenFileDialog openFileDialog = new OpenFileDialog();openFileDialog.Filter = "XPS Document Files(*.xps)|*.xps";if (openFileDialog.ShowDialog() == true)return openFileDialog.FileName;elsereturn null;}

这个静态方法主要是显示选择对话框以提供文件的保存位置。

保存XPS文件
public static bool SaveXPS(FixedPage page,bool isSaved) {FixedDocument fixedDoc = new FixedDocument();//创建一个文档 fixedDoc.DocumentPaginator.PageSize = new Size(96 * 8.5, 96 * 11);PageContent pageContent = new PageContent();((IAddChild)pageContent).AddChild(page);fixedDoc.Pages.Add(pageContent);//将对象到当前文档中string containerName = GetXPSFromDialog(isSaved);if (containerName != null){try{File.Delete(containerName);}catch (Exception e) {MessageBox.Show(e.Message);}XpsDocument _xpsDocument = new XpsDocument(containerName, FileAccess.Write);XpsDocumentWriter xpsdw = XpsDocument.CreateXpsDocumentWriter(_xpsDocument);xpsdw.Write(fixedDoc);//写入XPS文件_xpsDocument.Close();return true;}else return false;}

 这个方法主要是实现保存XPS文件。

装入到显示容器
static XpsDocument xpsPackage = null;public static void LoadDocumentViewer(string xpsFileName, DocumentViewer viewer){XpsDocument oldXpsPackage = xpsPackage;//保存原来的XPSxpsPackage = new XpsDocument(xpsFileName, FileAccess.Read, CompressionOption.NotCompressed);//从文件中读取文档FixedDocumentSequence fixedDocumentSequence = xpsPackage.GetFixedDocumentSequence();//从XPS文档对象得到FixedDocumentSequenceviewer.Document = fixedDocumentSequence as IDocumentPaginatorSource;if (oldXpsPackage != null)oldXpsPackage.Close();xpsPackage.Close();}

 这个方法是为了将XPS文件中文档装入到DocumentViewer显示容器中。

  2、 为了不至于通过硬编码的方式添加文档,我们添加了一个FixedPage页,注意由于FixedPage类明确标明是sealed,所以我们也不能添加代码隐藏文件,也只能在XAML添加元素,通过上下文DataContext来实现数据的绑定。这里我们添加了一个PrintView的FixedPage页,当然这里还用到了数据的绑定。相关的代码: 

FixedPage
<FixedPage xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"x:Name="Window" UseLayoutRounding="True"Width="640" Height="480"><Grid x:Name="LayoutRoot" DataContext="{Binding Collection, Source={StaticResource SimpleDataSource}}" ><ComboBox x:Name="dataCombo" VerticalAlignment="Bottom" Margin="-26,0,22,-503" Opacity="0" ItemsSource="{Binding Mode=OneWay}"/><Grid x:Name="frame" Margin="0,0,0,0" ><Canvas Margin="0,0,116,8"><Rectangle Margin="0" Stroke="Black" Fill="#FF4B4B9F" Opacity="0.4" RadiusX="5" RadiusY="5" Width="637" Height="473" Canvas.Left="3" Canvas.Top="2"/><Grid Height="422" Width="506" Canvas.Left="70" Canvas.Top="34" DataContext="{Binding SelectedItem, ElementName=dataCombo}"><Grid.RowDefinitions><RowDefinition Height="Auto"/><RowDefinition Height="Auto"/><RowDefinition/></Grid.RowDefinitions><Label x:Name="name" Content="{Binding Name}" FontSize="48" FontFamily="Script MT Bold" Margin="0" HorizontalAlignment="Center"/><Label x:Name="prescription" Content="{Binding Photo}" FontSize="48" FontFamily="Script MT Bold" Margin="0" HorizontalAlignment="Center" Grid.Row="1"/><Image x:Name="photo" Margin="8,0" Grid.Row="2" Source="{Binding Prescription}"/></Grid></Canvas></Grid></Grid></FixedPage>

 3、 添加了一个Window窗体,里面嵌入一个DocumentViewer对象以作为XPS文档的显示用的PrintWindow。

PrintWindow
<Windowxmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"x:Class="Workpiece.PrintWindow"x:Name="Window"Title="PrintWindow"UseLayoutRounding="True"Width="640" Height="480" Loaded="Window_Loaded"><Grid x:Name="LayoutRoot"><DocumentViewer x:Name="docViewer" /></Grid></Window>

  同时在后置代码文件中重载了Loaded事件,以装载文档

Loaded事件
      //传递一个公共的数据类        public string fixedDocFile;        private void Window_Loaded(object sender, RoutedEventArgs e)        {           FileHelper.LoadDocumentViewer(fixedDocFile, docViewer);        }

4、 为了传递数据到文档中,在Expression Blend中添加了一个示例的数据源。

5、 在主页面里我们实现了动态加载打印页面的方式,这里是通过Application类的LoadComponent()方法来实现的,在之前我也通过用XamlReader类的Load方法来加载过,不过使用这个方法,必须要将*.xaml文件设置成Building Action设置成Content,不然会出现发布时找不到数据文件的异常。相应的方法如下: 

显示调用
private void resutlBtn_Click(object sender, System.Windows.RoutedEventArgs e){// TODO: Add event handler implementation here.Uri printViewUri = new Uri("/Workpiece;Component/PrintView.xaml", UriKind.Relative);FixedPage printPage=(FixedPage )Application.LoadComponent(printViewUri);ComboBox combo = printPage.FindName("dataCombo") as ComboBox;combo.SelectedIndex = nameCombo.SelectedIndex;//数据同步FileHelper.SaveXPS(printPage, false);string xpsFileName = FileHelper.GetXPSFromDialog(false);//得到临时的文件存储PrintWindow window = new PrintWindow();window.fixedDocFile = xpsFileName;window.Show();}

6、 实现存储XPS文件的方法

XPS文件保存
//保存文件private void otherBtn_Click(object sender, System.Windows.RoutedEventArgs e){Uri printViewUri = new Uri("/Workpiece;Component/PrintView.xaml",UriKind.Relative);FixedPage printPage = (FixedPage)Application.LoadComponent(printViewUri);ComboBox combo = printPage.FindName("dataCombo") as ComboBox;combo.SelectedIndex = nameCombo.SelectedIndex;//数据同步if (FileHelper.SaveXPS(printPage, true))MessageBox.Show(string.Format("文件保存成功"));elseMessageBox.Show("取消文件保存"); } 

至此,实现了固定文档的XPS打印和显示功能。示例

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!