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

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
简介: 原文:【Win10应用开发】自定义打印选项 老周在前一篇烂文中已经给大伙伴们演示了如何打印UI元素,今天的烂文就向各位介绍一下,如何向打印对话框添加自定义选项。如果只是讲如何实现,会比较抽象,也比较枯燥,而且相当无聊,更是说不清楚,毕竟这打印API用起来要比其他API稍稍复杂了一点。

原文:【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();
                  });
            }
        }


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

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

运行后如下图:

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

 

最后看看打印结果。

 

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

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

 

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
目录
相关文章
|
12月前
|
存储 消息中间件 设计模式
win32概述及框架
win32概述及框架
260 0
|
存储 JavaScript Java
HarmonyOS应用开发——使用HUAWEI DevEco Studio创建第一个程序 HELLO WORLD!
HarmonyOS应用开发——使用HUAWEI DevEco Studio创建第一个程序 HELLO WORLD!
HarmonyOS应用开发——使用HUAWEI DevEco Studio创建第一个程序 HELLO WORLD!
|
安全
QingScan 快速集成自定义工具
QingScan是一个漏洞扫描聚合平台,添加目标后30款工具自动调用;不少人也想自己添加工具进来,其实添加非常简单,我们已经帮你考虑好了,你不用写代码只需要在界面操作就可以完成。
142 0
QingScan 快速集成自定义工具
|
安全 C# Windows
[UWP]在应用开发中安全使用文件资源
原文:[UWP]在应用开发中安全使用文件资源 在WPF或者UWP应用开发中,有时候会不可避免的需要操作文件系统(创建文件/目录),这时候有几个坑是需要大家注意下的。 创建文件或目录时的非法字符检测 在Windows系统中,我们创建文件时会注意到,某些特殊字符是不可以用作文件名输入的。
1015 0
|
Windows
【Win 10 应用开发】应用预启动
原文:【Win 10 应用开发】应用预启动 所谓预启动,其实你一看那名字就知道是啥意思了,这是直接译,也找不到比这个叫法更简练的词了。在系统资源允许的情况下(比如电池电量充足,有足够的内存空间),系统会把用户常用的应用程序在后台启动,但不会显示用户界面。
982 0
|
Windows 开发工具 git
win10 uwp 访问解决方案文件
原文:win10 uwp 访问解决方案文件 本文讲如何访问解决方案资源管理器的文件(文件属性->生成操作->内容)。 我们经常会把一些图片资源放在我们的解决方案,那么从这里拿出来很简单。 我在 Assets 放了图片 1.
871 0