老周在前一篇烂文中已经给大伙伴们演示了如何打印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(, 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();
});
}
}

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

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

运行后如下图:

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

最后看看打印结果。

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

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

【Win10应用开发】自定义打印选项的更多相关文章

  1. Win10 UWP开发系列:使用VS2015 Update2+ionic开发第一个Cordova App

    安装VS2015 Update2的过程是非常曲折的.还好经过不懈的努力,终于折腾成功了. 如果开发Cordova项目的话,推荐大家用一下ionic这个框架,效果还不错.对于Cordova.PhoneG ...

  2. Win10/UWP开发—使用Cortana语音与App后台Service交互

    上篇文章中我们介绍了使用Cortana调用前台App,不熟悉的移步到:Win10/UWP开发—使用Cortana语音指令与App的前台交互,这篇我们讲讲如何使用Cortana调用App的后台任务,相比 ...

  3. [转]jquery开发自定义的插件总结

    本文转自:http://www.cnblogs.com/Jimmy009/archive/2013/01/17/jquery%E6%8F%92%E4%BB%B6.html 前几天在玩jquery,今天 ...

  4. 基于Spring的可扩展Schema进行开发自定义配置标签支持

    一.背景 最近和朋友一起想开发一个类似alibaba dubbo的功能的工具,其中就用到了基于Spring的可扩展Schema进行开发自定义配置标签支持,通过上网查资料自己写了一个demo.今天在这里 ...

  5. Win 10 开发中Adaptive磁贴模板的XML文档结构,Win10 应用开发中自适应Toast通知的XML文档结构

    分享两篇Win 10应用开发的XML文档结构:Win 10 开发中Adaptive磁贴模板的XML文档结构,Win10 应用开发中自适应Toast通知的XML文档结构. Win 10 开发中Adapt ...

  6. BizTalk开发系列(二十二) 开发自定义Map Functoid

    尽管 BizTalk Server 提供许多Functoid以支持一系列不同的操作,但仍可能会遇到需要其他方法的情况.<BizTalk开发系列 Map扩展开发>介绍了通过使用自定义 XSL ...

  7. 开发自定义View

    当开发者打算派生自己的UI组件时,首先定义一个继承View基类的子类,然后重写View类的一个或多个方法,通常可以被用户重写的方法如下:构造器:重写构造器是定制View的最基本方法,当Java代码创建 ...

  8. JSP进阶 之 SimpleTagSupport 开发自定义标签

    绝大部分 Java 领域的 MVC 框架,例如 Struts.Spring MVC.JSF 等,主要由两部分组成:控制器组件和视图组件.其中视图组件主要由大量功能丰富的标签库充当.对于大部分开发者而言 ...

  9. 记微信开发(自定义回复&关注回复)

    记微信开发(自定义回复&关注回复) 记微信开发(自定义回复&关注回复) code: <?php/** * wechat php test *///define your toke ...

  10. 在 Visual C++ 中开发自定义的绘图控件

    本文讨论的重点介于两者 之间 — 公共控件赋予您想要的大部分功能,但控件的外观并不是您想要的.例如,列表视图控件提供在许多视图风格中显示数据列表的方式 — 小图标.大图标.列表和详细列表(报告).然而 ...

随机推荐

  1. CODEVS1090 加分二叉树

    codevs1090 加分二叉树 2003年NOIP全国联赛提高组 题目描述 Description 设一个n个节点的二叉树tree的中序遍历为(l,2,3,…,n),其中数字1,2,3,…,n为节点 ...

  2. Java数据结构——栈的应用(以数制转换为例子)

    看一万遍,不如自己动手实践,请不要直接copy代码,先自己去理解例子实现的原理,然后试着自己动手去实践. 用Java去实现栈操作,会用到stack这个类,这类中有几个方法需要知道他们的用法  bool ...

  3. 【总结】C# 设置委托的机理和简要步骤

    [引语]实际上,和Winform打交道的第一天呢,我们就已经接触了委托,例如当双击button产生button1_click,这个呢,是对button1点击事件的处理方法,至于委托和订阅事件,就悄悄的 ...

  4. BZOJ2506: calc

    Description            给一个长度为n的非负整数序列A1,A2,…,An.现有m个询问,每次询问给出l,r,p,k,问满足l<=i<=r且Ai mod p = k的值 ...

  5. android开发中使不同的listview同时联动

    在做一个Android程序时,需要在一个屏幕上显示两个不同的listview,开始用< linearlayout>包裹这两个listview在<ScrollView >设置时, ...

  6. 基础2.Jquery过滤选择器

                         1.基础选择器: 名称 说明 举例 #id 根据元素Id选择 $("divId") 选择ID为divId的元素 element 根据元素的 ...

  7. iOS中 将 颜色转化成图片

    定义一个类方法: 声明: + (UIImage *)imageFromColor:(UIColor *)color; 实现: + (UIImage *)imageFromColor:(UIColor ...

  8. tabhost 下 setOnItemClickListener失效的问题

    分析了一下代码,应该是tabhost 的ontabchangedListener接管了下面应该由setOnItemClickListener接管的部分,导致不能相应setOnItemClickList ...

  9. HDU--跑道相遇

    跑道相遇 Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)Total Submis ...

  10. 使用epel源安装软件

    问题:centos提供的官方base源可能无法提供某些软件的安装,可以通过epel源 系统:centos6.5 x86_64 解决:安装epel源 #wget http://dl.fedoraproj ...