转载

【Win10应用开发】自定义打印选项

老周在前一篇烂文中已经给大伙伴们演示了如何打印UI元素,今天的烂文就向各位介绍一下,如何向打印对话框添加自定义选项。如果只是讲如何实现,会比较抽象,也比较枯燥,而且相当无聊,更是说不清楚,毕竟这打印API用起来要比其他API稍稍复杂了一点。所以老周就做了一个打印图片的垃圾应用,在打印对话框中,你可以选择设置要打印图片的不透明度、旋转角度(0度,90度,180度,270度)。

OK,为环保事业做贡献,老周今天也节约一点口水。下面咱们开始干活。

1、先来设计一些UI,该UI简单大方朴素美丽极致,其XAML代码如下:

<Grid>  <Grid.RowDefinitions>   <RowDefinition Height="auto"/>   <RowDefinition Height="*"/>  </Grid.RowDefinitions>  <Button Content="打印" Click="OnClick"/>  <Image Grid.Row="1" Width="300" Height="200" VerticalAlignment="Center" HorizontalAlignment="Center" Name="img"  Source="Assets/03.jpg"/> </Grid> 

按钮的作用就是打开打印对话框,Image显示要打印的图片。不过呢,为了打印过程中设置选项(就是老周上面讲的什么不透明度等)时不会干扰界面上的Image,我打算在代码中再声明一个Image对象,专门用来打印。代码是这样的:

Image copyImage = null; public MainPage() {  this.InitializeComponent();  copyImage = new Image();  copyImage.Source = img.Source;  copyImage.Stretch = Stretch.Uniform;  rotateTrsf = new RotateTransform() { Angle = 0d };  copyImage.RenderTransformOrigin = new Point(0.5, 0.5);  this.copyImage.RenderTransform = rotateTrsf; } 

大家会看到我弄了个RotateTransform对象,干啥用的呢?你忘了吗,我刚说了要在打印对话框中选择图片的旋转角度的,对了,就是用来让copyImage进行旋转的。

2、接下来实现打印,基本过程我在前一篇烂文中说过,获取PrintManager实例,处理PrintTaskRequested事件,当有新的打印任务请求时,会发生该事件。看:

private void PrintMgr_PrintTaskRequested(PrintManager sender, PrintTaskRequestedEventArgs args)         {  PrintTask task = null;  task = args.Request.CreatePrintTask("打印图像", async printSrcrqtArgs =>  {      task.Completed += async (ps, pe) =>      {          await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, async () =>       {           MessageDialog msgdlg = new MessageDialog("");           if (pe.Completion == PrintTaskCompletion.Canceled)           {    msgdlg.Content = "打印被取消。";           }           else if (pe.Completion == PrintTaskCompletion.Abandoned)           {    msgdlg.Content = "已放弃打印。";           }           else if (pe.Completion == PrintTaskCompletion.Submitted)           {    msgdlg.Content = "已提交打印。";           }           await msgdlg.ShowAsync();       });      };      await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>        {            printSrcrqtArgs.SetSource(_printdoc?.DocumentSource);        });  });  task.Options.Orientation = PrintOrientation.Landscape;  // 创建自定义选项  PrintTaskOptionDetails optionDetails = PrintTaskOptionDetails.GetFromPrintTaskOptions(task.Options);  // 清除所有选项  optionDetails.DisplayedOptions.Clear();  // 添加标准项:页面方向  optionDetails.DisplayedOptions.Add(StandardPrintTaskOptions.Orientation);  // 添加自定义选项  // 不透明度  PrintCustomItemListOptionDetails list = optionDetails.CreateItemListOption(OPTION_OPACITY, "不透明度");  list.AddItem(OPACITY_50PC, "50 %");  list.AddItem(OPACITY_75PC, "75 %");  list.AddItem(OPACITY_100PC, "100 %");  optionDetails.DisplayedOptions.Add(OPTION_OPACITY);  // 旋转角度  list = optionDetails.CreateItemListOption(OPTION_ANGLE, "旋转角度");  list.AddItem(ANGLE_0, "0 度");  list.AddItem(ANGLE_90, "90 度");  list.AddItem(ANGLE_180, "180 度");  list.AddItem(ANGLE_270, "270 度");  optionDetails.DisplayedOptions.Add(OPTION_ANGLE);  // 处理选项更改事件  optionDetails.OptionChanged += OptionDetails_OptionChanged;         } 

为了节约代码行数,同时为了展现C#语言的风采,我这里套用了几层Lambda表达式。

请大伙注意后半段代码,前半段代码你应该在前一篇烂文中见过,但后半段代码是小鲜肉,在本文中才出现,它的作用是向打印对话框中添加标准的,以及自定义的选项。

何为标准选项?就是一般打印参数(通用级别),这些选项的ID名称都由Windows.Graphics.Printing.StandardPrintTaskOptions类的静态属性所公开。

自定义选项就咱们自己定的选项,本例中,图片透明度、旋转角度就是自定义选项。

a、PrintTaskOptionDetails.GetFromPrintTaskOptions方法获取一个PrintTaskOptionDetails对象,可用它来操作选项集合。

b、PrintTaskOptionDetails对象有个DisplayedOptions属性,它是一个字符串列表,表示要在打印对话框上显示哪些选项,就把这些选项的ID放进去。没有在这个列表中的项就只有当用户点击“更多设置”时才会显示。

c、这行代码是把标准选项中的页面方向选项加到显示列表中,因为刚才用Clear方法把DisplayedOptions清空了,所以要加入一下。

optionDetails.DisplayedOptions.Add(StandardPrintTaskOptions.Orientation);

d、调用CreateItemListOption方法可以创建一个新的自定义选项,方法有两个字符串类型的参数,第一个参数是这组选项的ID,第二个参数是显示的内容,即要显示在打印对话框上的选项标题,ID是不显示出来的。e、用AddItem方法添加子选项时也是如此,一个ID值和一个显示值。

注意:CreateItemListOption方法创建的是整个选项组,比如“旋转方向”,而AddItem方法才是向选项组添加列表项,比如90度、180度等。

f、选项列表是添加了,但为了在打印对话框中能够实时看到预览效果,应该处理Windows.Graphics.Printing.OptionDetails.PrintTaskOptionDetails对象的OptionChanged事件,当这些选项集合中的任意一组选项发生改变时就会触发事件。

private async void OptionDetails_OptionChanged(PrintTaskOptionDetails sender, PrintTaskOptionChangedEventArgs args)         {             if (args.OptionId == null) return;             string optID = args.OptionId as string;
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () => { _printdoc.InvalidatePreview(); }); }

事件参数中的OptionId属性就是返回被更改的选项组的ID。注意是某个组选项的ID,不是单个子项的ID。调用PrintDocument的InvalidatePreview方法是让PrintDocument中的UI元素重新呈现,和刷新差不多。

==================================================

和上一篇烂文中的一样,需要处理PrintDocument对象的几个事件,以处理打印和预览中相关的操作。

private void _printdoc_Paginate(object sender, PaginateEventArgs e)   {    // 根据打印对话框选项的变化来修改可视化对象    PrintTaskOptionDetails optdetails = PrintTaskOptionDetails.GetFromPrintTaskOptions(e.PrintTaskOptions);    // 不透明度    IPrintOptionDetails opaOpt = optdetails.Options[OPTION_OPACITY];    string opacity = opaOpt.Value as string;    switch (opacity)    {     case OPACITY_50PC:      copyImage.Opacity = 0.5d;      break;     case OPACITY_75PC:      copyImage.Opacity = 0.75d;      break;     case OPACITY_100PC:      copyImage.Opacity = 1d;      break;     default:      copyImage.Opacity = 1d;      break;    }    // 旋转角度    IPrintOptionDetails angleOpt = optdetails.Options[OPTION_ANGLE];    string angle = angleOpt.Value as string;    switch (angle)    {     case ANGLE_0:      rotateTrsf.Angle = 0d;      break;     case ANGLE_90:      rotateTrsf.Angle = 90d;      break;     case ANGLE_180:      rotateTrsf.Angle = 180d;      break;     case ANGLE_270:      rotateTrsf.Angle = 270d;      break;     default:      rotateTrsf.Angle = 0d;      break;    }    // 设置预览页面数    _printdoc.SetPreviewPageCount(1, PreviewPageCountType.Final);   }   private void _printdoc_GetPreviewPage(object sender, GetPreviewPageEventArgs e)   {    // 呈现预览    try    {     _printdoc.SetPreviewPage(e.PageNumber, copyImage);    }    catch    {     // 发生异常时忽略    }   }   private void _printdoc_AddPages(object sender, AddPagesEventArgs e)   {    // 添加要打印的页面    _printdoc.AddPage(copyImage);    // 报告添加完成    _printdoc.AddPagesComplete();   } 

在GetPreviewPage事件处理中把代码放在try...catch中,是防止发生异常。因为标准打印选项的更改本身就会引发重绘行为,但我们这里是把标准项和自定义项混在一起用,有发生异常的可能性,所以放到try中安全一些。

如果不把代码放在try块中,其实还有一种方法:就是在刚才的OptionChanged事件的处理过程中,只判断当OptionId是我们自定义的选项组时才调用PrintDocument的InvalidatePreview方法,如果是标准选项就会忽略,这样就不会发生异常。即

private async void OptionDetails_OptionChanged(PrintTaskOptionDetails sender, PrintTaskOptionChangedEventArgs args) {  if (args.OptionId == null) return;  string optID = args.OptionId as string;  if (optID == OPTION_OPACITY || optID == OPTION_ANGLE)  {   await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>     {       _printdoc.InvalidatePreview();     });     } } 

=====================================================

不知不觉中,示例已经完成了,现在来运行一下。

运行后如下图:

【Win10应用开发】自定义打印选项

点打印按钮,打开打印对话框。在打印对话框中,你可以进行参数设置。

【Win10应用开发】自定义打印选项

最后看看打印结果。

【Win10应用开发】自定义打印选项

好了,今天咱们就聊到这儿,下次有空咱们继续吹牛。

示例下载地址:http://files.cnblogs.com/files/tcjiaan/customPrintOptionSample.zip

正文到此结束
Loading...