老周在前一篇烂文中已经给大伙伴们演示了如何打印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. 弄清 CSS3 的 transition 和 animation

    弄清 CSS3 的 transition 和 animation transition transition 属性是 transition-property, transition-duration, ...

  2. 【SRM】518 Nim

    题意 \(K(1 \le K \le 10^9)\)堆石子,每堆石子个数不超过\(L(2 \le 50000)\),问Nim游戏中先手必败局面的数量,答案对\(10^9+7\)取模. 分析 容易得到\ ...

  3. Dictionary Learning(字典学习、稀疏表示以及其他)

    第一部分 字典学习以及稀疏表示的概要 字典学习(Dictionary Learning)和稀疏表示(Sparse Representation)在学术界的正式称谓应该是稀疏字典学习(Sparse Di ...

  4. 一些ES5的操作数组的方法

    在ES5规范中新增了不少操作数组的方法,特此罗列一下以备使用 1. forEach循环 有点类似jQuery的each循环 [12,23,36,4,5].forEach(function(v,k){ ...

  5. HOW TO RUN A SPRINT PLANNING MEETING (THE WAY I LIKE IT)

    This is a sample agenda for a sprint planning meeting. Depending on your context you will have to ch ...

  6. String对象方法扩展

    /** *字符串-格式化 */ String.prototype.format = function(){ var args = arguments;//获取函数传递参数数组,以便在replace回调 ...

  7. git 常用操作命令

    A. 新建Git仓库,创建新文件夹git init B. 添加文件到git索引git add <filename>  --- 单个文件添加git add * --- 全部文件添加 C. 提 ...

  8. 串口计时工具Grabserial简介及修改(添加输入功能)

    Grabserial是Tim Bird用python写的一个抓取串口的工具,这个工具能够为收到的每一行信息添加上时间戳. 如果想对启动时间进行优化的话,使用这个工具就可以简单地从串口输出分析出耗时. ...

  9. Struts2使用demo

    创建一个web project: 导入Struts2的jar包放到lib目录下: WEB-INF下面创建login.jsp和welcome.jsp;index.jsp删掉: 说一下<%@ tag ...

  10. JS鼠标获取坐标

    <html> <head> <title>获取鼠标的坐标信息</title> </head> <body> <div id ...