【Win 10 应用开发】打印UI元素

原文:【Win 10 应用开发】打印UI元素

Windows App支持将UI界面进行打印的功能,这与浏览器中的打印网页的用途相近,其好处就是“所见即所得”,直接把界面上呈现的内容打印下来,比重新创建打印图像方便得多。

要在通用App中实现打印,主要依靠以下几个类型:

PrintManager:位于Windows.Graphics.Printing命名空间,主要负责显示打印对话框,设置打印源等操作。在使用时,首先调用GetForCurrentView静态方法得到一个PrintManager实例;随后处理它的PrintTaskRequested,当要进行打印时就会发生该事件。

PrintTask:表示一个打印任务。在PrintManager对象的PrintTaskRequested事件处理中创建打印任务。

PrintDocument:这个类比较关键(位于Windows.UI.Xaml.Printing命名空间)。通过它可以将UI元素转换为待打印的文档逻辑。a、处理Paginate事件,以计算打印的分页,计算后可以调用PrintDocument.SetPreviewPageCount方法来设置预览页面的总数。b、处理GetPreviewPage事件,当请求预览单个页面时会发生该事件,在处理过程中,可以调用PrintDocument.SetPreviewPage方法来设置要预览的特定页面。c、当开始打印时,会发生AddPages事件,此时调用PrintDocument.AddPage方法向打印文档逻辑添加页面,当所有要打印的页面都添加完毕后,请调用AddPagesComplete方法通知系统可以提交打印了。

当你刚刚接触打印时,你会觉得它好像很复杂,其实,当你动手做过实验后,你就会发现,其实也没什么。我们作为新时代的开发者,应当有迎难而上的精神。

下面咱们来做个例子,把页面上的一个RichTextBlock控件中的内容打印出来。

页面上的XAML大致如下,老周直接贴出来,不作解释了,我相信你能看懂XAML,如果看不懂,那就算了。

    <Border Padding="30" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="auto"/>
                <RowDefinition/>
                <RowDefinition Height="auto"/>
            </Grid.RowDefinitions>
            <StackPanel Margin="0,15" Orientation="Horizontal">
                <Button Content="开始打印" Click="OnClick"/>
            </StackPanel>
            <RichTextBlock Name="tb" Grid.Row="1" Width="300" >
                <Paragraph FontSize="36" TextAlignment="Center" FontFamily="楷体">
                    床前明月光,
                    <LineBreak/>
                    疑是地上霜。
                    <LineBreak/>
                    舉頭望明月,
                    <LineBreak/>
                    低頭思故鄉。
                </Paragraph>
                <Paragraph TextAlignment="Center">
                    <InlineUIContainer>
                        <Image Height="200" Source="http://img155.poco.cn/mypoco/myphoto/20110305/15/20110305154657_366496406.gif"/>
                    </InlineUIContainer>
                </Paragraph>
            </RichTextBlock>

            ……
        </Grid>
    </Border>

咱们这例子要打印的内容,就是那个名为tb的家伙。

进入页面的代码文件,在页面类中声明以下字段:

        PrintManager printmgr = PrintManager.GetForCurrentView();
        PrintDocument printDic = null;
        RotateTransform rottrf =null;
        PrintTask task = null;

RotateTransform变量的作用是把tb进行旋转变换,这是为了处理打印页面的方向,如果页面是横向,我就把tb转90度。

处理PrintManager的PrintTaskRequested事件,创建打印任务,并设置打印源。

       printmgr.PrintTaskRequested += Printmgr_PrintTaskRequested;
       ……
        private void Printmgr_PrintTaskRequested(PrintManager sender, PrintTaskRequestedEventArgs args)
        {
            var def = args.Request.GetDeferral();
            // 创建打印任务
            task = args.Request.CreatePrintTask("打印测试", OnPrintTaskSourceRequrested);
            task.Completed += Task_Completed;
            def.Complete();
        }

在调用CreatePrintTask方法创建打印任务时,有一个参数需要通过一个委托来设置打印源。所谓打印源,就是我们要打印的文档

        private async void OnPrintTaskSourceRequrested(PrintTaskSourceRequestedArgs args)
        {
            var def = args.GetDeferral();
            await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal,
                () =>
                {
                    // 设置打印源
                    args.SetSource(printDic?.DocumentSource);
                });
            def.Complete();
        }

我们这里要打印的其实就是PrintDocument对象,我们变量命名好像错了,叫printDoc合理一些,我打成了printDic。没事,大家知道就OK了。

下面代码处理按钮的单击事件:

        private async void OnClick(object sender, RoutedEventArgs e)
        {
            if (printDic != null)
            {
                printDic.GetPreviewPage -= OnGetPreviewPage;
                printDic.Paginate -= PrintDic_Paginate;
                printDic.AddPages -= PrintDic_AddPages;
            }
            this.printDic = new PrintDocument();
            printDic.GetPreviewPage += OnGetPreviewPage;
            printDic.Paginate += PrintDic_Paginate;
            printDic.AddPages += PrintDic_AddPages;

            // 显示打印对话框
            bool b=await PrintManager.ShowPrintUIAsync();
        }

在实例化PrintDocument后,要处理它的几个事件。

先处理AddPages事件,这个事件是在开始执行打印时才会发生,在事件处理中要向打印文档添加页面,每个页面的内容就是我们要打印的UI元素,为了简单,老周只打印一页。

        private void PrintDic_AddPages(object sender, AddPagesEventArgs e)
        {
            // 添加要打印的页
            printDic.AddPage(tb);
            // 报告添加完成
            printDic.AddPagesComplete();
        }

处理Paginate事件,这个事件在打开打印对话框时发生,并且如果用户调整了打印对话框中的参数后也会发生(比如修改了页面方向),目的是重新计算页面的预览。

        private void PrintDic_Paginate(object sender, PaginateEventArgs e)
        {
            PrintTaskOptions opt = task.Options;
            // 根据页面的方向来调整打印内容的旋转方向
            switch (opt.Orientation)
            {
                case PrintOrientation.Default:
                    rottrf.Angle = 0d;
                    break;
                case PrintOrientation.Portrait:
                    rottrf.Angle = 0d;
                    break;
                case PrintOrientation.Landscape:
                    rottrf.Angle = 90d;
                    break;
            }

            // 设置预览页面的总页数
            printDic.SetPreviewPageCount(1, PreviewPageCountType.Final);
        }

下面代码添加特定页面的预览。

        private void OnGetPreviewPage(object sender, GetPreviewPageEventArgs e)
        {
            // 设置要预览的页面
            printDic.SetPreviewPage(e.PageNumber, this.tb);
        }

大家要注意,页面预览和实际打印是两回事,因此SetPreviewPage只是设置要预览的UI元素,而实际打印是要在AddPages事件中通过AddPage方法来添加页面

当示例完成之时,大家可能又遇到问题了,我没有打印机,怎么办? 没事,老周很穷,也没有打印机,但不要忘记,系统里面有这些功能:

是啊,有它们就行,搜索“设备与打印机”就能找到它们,所以在运行示例后,直接把内容打印为.pdf文档就可以了,打印完后,.pdf文件存到“文档”目录中。

现在运行应用程序,然后点击“开始打印”按钮。

然后会弹出打印对话框。

确认开始打印,点击“打印”按钮。打印完成后系统会以Toast通知来提醒你。下图所示是打印出来的.pdf文件。

好了,是不是有点高大上的感觉呢?

示例代码下载:http://files.cnblogs.com/files/tcjiaan/printSample.zip

时间: 2024-10-12 17:28:01

【Win 10 应用开发】打印UI元素的相关文章

【Win 10 应用开发】UI Composition 札记(一):视图框架的实现

在开始今天的内容之前,老周先说一个问题,这个问题记得以前有人提过的. 设置 Windows.ApplicationModel.Core.CoreApplicationView.TitleBar.ExtendViewIntoTitleBar 属性可以让应用窗口中的内容扩展到标题栏.简单地说,就是你的UI区域可以扩大,并填充到标题栏,这在开发自定义标题栏或弄个什么毛玻璃效果时很有用. 不过,这个 ExtendViewIntoTitleBar 属性有个“八阿哥”,一旦你设置之后,系统会对其进行记录,很

【Win 10 应用开发】UI Composition 札记(三):与 XAML 集成

除了 DirectX 游戏开发,我们一般很少单独使用 UI Composition ,因此,与 XAML 互动并集成是必然结果.这样能够把两者的优势混合使用,让UI布局能够更灵活. 说到与 XAML 的集成,则我们必须先认识一位伙计,他非常重要,位于 Windows.UI.Xaml.Hosting 命名空间下,名叫 ElementCompositionPreview ,有了它,我们才可以在 XAML 元素与 Composition UI 元素之间游走.来看看它都公开了哪些成员. public s

【Win 10 应用开发】UI Composition 札记(八):用 XamlLight 制作灯光效果

前面老周已介绍过灯光的使用,如果你忘了,请用九牛二虎之力猛点击这里去复习一下.本篇老周再介绍另一种添加灯光的方法,这种方法是专为 XAML 元素而设计的,可以很方便地为可视化元素添加灯光效果. 不知道大伙伴是否发现,UIElement 类公开了一个 Lights 属性(15063,v1703,或更高版本),它是一个列表,可以添加若干个 XamlLight 对象.通过这个属性,我们也能为 XAML 可视化元素设置灯光. 虽然我们看到 XamlLight 类有构造函数,但是,它不是直接使用的,因为它

【Win 10 应用开发】UI Composition 札记(四):绘制图形

使用 Win 2D 组件,就可以很轻松地绘制各种图形,哪怕你没有 D2D 相关基础,也不必写很复杂的 C++ 代码. 先来说说如何获取 Win 2D 组件.很简单,创建 UWP 应用项目后,你打开“解决方案资源管理器”窗口,然后在[引用]节点上右击,从快捷菜单中选择[管理 Nuget 程序包]命令,在打开的窗口中搜索“Win 2D”,然后安装带有 uwp 标识的那个就可以了. 顺便说一下,nuget 的包缓存在你的用户文件夹下,就是系统盘下的 \users\xxx,xxx是你登录系统的用户名,在

【Win 10 应用开发】UI Composition 札记(六):动画

动画在 XAML 中也有,而且基本上与 WPF 中的用法一样.不过,在 UWP 中,动画还有一种表现方式—— 通过 UI Composition 来创建. 基于 UI Composition 的动画,相对于 XAML 动画,有以下优点: 1.不使用 UI 线程,XAML 动画是共享 UI 线程的,而 Composition 中的动画是使用辅助线程的. 2.Composition 动画支持表达式(计算公式)来产生动画,相对灵活. 老周的建议是:两者都用,因为基于 XAML 和基于 Composit

【Win 10 应用开发】UI Composition 札记(七):基于表达式的动画

上一篇烂文中,老周给大伙伴们介绍过了几个比较好玩的动画.本篇咱们深化主题,说一说基于表达式的动画.这名字好理解,就是你可以用公式 / 等式来产生动画的目标值.比如,你想让某个可视化对象的高度减半,你的表达可以这样写: width / 2,其中,width 表示某对象的宽度. 既然说到基于表达式的动画了,就得介绍一个重要的类型:ExpressionAnimation,它专用来实现表达式动画的.它有一个 Expression 属性,字符串类型,用来设置计算动画目标值的等式. 有关表达式的语法,老周就

【Win 10应用开发】如何知道当前APP在哪个平台设备上运行

[Win 10应用开发]如何知道当前APP在哪个平台设备上运行 在做Win10开发的时候,我们可能经常会需要获得当前程序在在哪个平台设备上运行,用于UI和相关API的调用,那么可以通过什么方式知道当前APP运行的平台呢? 今天这里提供两个方法给大家做参考: 方法一:DeviceFamily 通过Windows.System.Profile.AnalyticsInfo.VersionInfo.DeviceFamily,来获取当前的平台设备,目前只可以得到两个值Windows.Mobile或Wind

【Win 10应用开发】实现全屏播放的方法

原文:[Win 10应用开发]实现全屏播放的方法 有人会问,以前的MediaElement控件不是有现成的一排操作按钮吗?而且可以直接进入全屏播放.是的,我们知道,以往的Store App都是在全屏模式下运行的,只要MediaElement控件填满整个窗口,就等于全屏播放了,但是,Win10应用是窗口化的,将MediaElement控件的IsFullWindow属性设置为true后,就会这样: 从上面的截图看,MediaElement控件只是覆盖整个窗口而已,并没有实现全屏.那有办法让它全屏播放

【Win 10 应用开发】Toast通知激活应用——前台&amp;后台

原文:[Win 10 应用开发]Toast通知激活应用--前台&后台 老周最近热衷于讲故事,接下来还是讲故事时间. 有人问我:你上大学的时候,有加入过学生会吗?读大学有没有必要加入学生会? 哎哟,这怎么回答呢,从短期来说,加入学生会有点用,至少可以娱乐一下,运气好的话,说不定能遇到红颜知己,但这概率相当低.从长远发展看嘛,是没什么用.老周当年读了四年本科,在学生会混了四年,什么名堂也没混出来. 一方面老周向来不求虚名,所以也没去参选所谓的什么部长.主席之类的,这些“官衔”听起来很高大上,实际上很