基于Silverlight打印的使用详解,是否为微软的Bug问题

1:新建Silverlight4 应用程序,名称为SLStudy。建好后如下:

2:在SLStudy下新建Silverlight用户控件,Print1.xaml作为要打印的控件。

在Print1.xaml里面添加代码为:


代码如下:

<Grid x:Name="LayoutRoot" Background="White">
      <Button>这是第一个例子,简单的按钮</Button>
</Grid>

3:已经建立好了要打印的内容了,这里打印的是一个按钮。

4:修改MainPage.xaml代码如下:


代码如下:

<Grid x:Name="LayoutRoot" Background="White">
        <StackPanel>
            <Button x:Name="btnPrint1" Click="btnPrint1_Click">Print1</Button>
        </StackPanel>
</Grid>

5:后台代码为:


代码如下:

private void btnPrint1_Click(object sender, RoutedEventArgs e)
        {
            PrintDocument printDocument = new PrintDocument();
            printDocument.PrintPage += new EventHandler<PrintPageEventArgs>(printDocument_PrintPage);
            PrintDocument.Print("要打印的文档的名称,这个可以随便设置");
        }

void printDocument_PrintPage(object sender, PrintPageEventArgs e)
        {
            e.PageVisual = new Print1();
        }

在SL4 中提供打印功能的是PrintDocument类,所以先实例化一个该类对象。

接着注册一个PrintPage事件,PrintPage事件在打印的时候会触发。

然后调用printDocument的Print方法来打印。

在PrintDocument的PrintPage事件中,PrintPageEventArgs,是打印的参数。

里面可以获取当前打印机的一些信息。

在这里设置PageVisual,也就是要打印的对象就可以了。


代码如下:

void printDocument_PrintPage(object sender, PrintPageEventArgs e)
{
  e.PageVisual = new Print1();
}

全部写好后,可以运行应用程序,点击Print1,弹出打印窗口。打印效果如下图:

当然我们的打印需求不可能这么简单,也许需要设置Print1的内容。假设我们要修改按钮显示的字,那么我们可以这样:


代码如下:

void printDocument_PrintPage(object sender, PrintPageEventArgs e)
{
    Print1 printVisual = new Print1();
    printVisual.btnSample.Content = "修改后的值,当然也可以从数据库中获取";
    e.PageVisual = printVisual;
}

通过设置PrintPageEventArgs 参数的PageVisual对象,我们就可以实现打印那个页面的功能了。

在这里我总结下:

1:确定要打印的内容,然后新建一个UserControl来显示打印的内容。

2:新建PrintDocument对象,注册PrintPage事件,调用Print方法。

3:在PrintPage事件中,构造要打印的对象,然后去数据库中获取数据,然后把数据绑定到控件上,接着把绑定好数据的控件赋值给PrintPageEventArgs的PageVisual 对象。

多页打印问题:

如果要打印的只有一张,那么这种方法应该就够了,但是有时候需要将一份文档打印多张,

比如将上面的按钮打印5张,那么又该如何实现了。

还记得我们上面PrintPageEventArgs的HasMorePages参数吗?

在PrintPage 事件触发后,默认的HasMorePages 为false。将HasMorePages设置为true,可以让PrintPage事件不断被触发。当 HasMorePages 属性为 true,PrintPage 事件将多次发生,直到 HasMorePages 为 false。

假设我们要将上面的按钮打印5张,那么可以设置4次HasMorePages为true,最后设置HasMorePages为false就可以了。

修改后的printDocument_PrintPage 方法如下:


代码如下:

int count = 5;
int printCount = 0;
void printDocument_PrintPage(object sender, PrintPageEventArgs e)
{
    Print1 printVisual = new Print1();
    printVisual.btnSample.Content = "修改后的值,当然也可以从数据库中获取";
    e.PageVisual = printVisual;
    printCount++;

if (printCount < count) //如果已经打印的页数小于要打印的页数,说明还需要打印。
    {
         e.HasMorePages = true;
    }
    else
    {
        e.HasMorePages = false;
    }
}

有时候需要知道当前打印的是第几页,这可以通过查询printDocument.PrintedPageCount 属性来获得,

在PrintDocument_PrintPage 方法中,sender对象其实就是PrintDocument对象,所以我们可以将它强制类型转换。

假设我们要将上面的5个 Button的内容都修改为1,2,3,4,5.那么我们可以修改代码为:


代码如下:

int count = 5;
        int printCount = 0;

void printDocument_PrintPage(object sender, PrintPageEventArgs e)
        {
            PrintDocument printDocument = sender as PrintDocument;
            Print1 printVisual = new Print1();
            printVisual.btnSample.Content = string.Format("按钮{0}", printDocument.PrintedPageCount);
            e.PageVisual = printVisual;
            printCount++;

if (printCount < count)
            {
                e.HasMorePages = true;
            }
            else
            {
                e.HasMorePages = false;
            }
        }

实际上,我们的printCount变量都不需要了,直接使用printDocument.PrintedPageCount 就可以了,具体代码实现由读者自己实现吧。

微软的Bug??

如果你的打印机设置为

那么打印的结果就是*.xps的文件,但是在打印的过程中会弹出提示框,询问保存地址。

如果你在PrintPage事件中打上断点的话,可以看到在询问保存地址的时候,PrintPage方法已经执行了,也就是说PringPage方法会被执行两遍,第一遍并没有真正的打印。

例如:

如果在上图的界面上点击取消,则有可能会导致系统失去响应而卡死,

假设用户点击保存,那么PrintPage事件会再次的触发。

但是由于已经打印了一次了,所以有可能导致在多页打印的时候出现问题。

使用两个标志变量可以解决这个问题。

例如修改代码为:

代码如下:

int count = 5;
        int printCount = 0;

/// <summary>
        /// 是否是第一次打印,因为只有第二次打印的时候才开始真正的打印。
        /// </summary>
        private bool isInitialized = false;
        private bool realPrint = false;

void printDocument_PrintPage(object sender, PrintPageEventArgs e)
        {
            PrintDocument printDocument = sender as PrintDocument;
            int currentPage = printDocument.PrintedPageCount;

#region 因为要经过两次,第一次是初始化,而第二次才是真正的打印,而两次PrintedPageCount都是0
            if (currentPage == 0)
            {
                if (isInitialized) //如果已经初始化,则设置realPrint为true
                {
                    realPrint = true;
                }

isInitialized = true; //运行到这里,说明已经初始化了。
            }
            #endregion

if (realPrint)
            {
                //PrintDocument printDocument = sender as PrintDocument;

Print1 printVisual = new Print1();
                printVisual.btnSample.Content = string.Format("按钮{0}", printDocument.PrintedPageCount);

e.PageVisual = printVisual;

printCount++;
                if (printCount < count)
                {
                    e.HasMorePages = true;
                }
                else
                {
                    e.HasMorePages = false;
                }
            }
        }

因为两次打印,第一次可以被认为是初始化,第二次可以被认为是打印机开始真正的打印,

所以可以使用两个变量isInitialized 和realPrint 来分别表示是初始化还是真实的打印。

在执行第一遍的时候printDocument.PrintedPageCount ==0,在这时候将isInitialized 设置为true。

在执行第二遍的时候,因为isInitialized ==true,所以可以将realPrint设置为true。

在后面的代码中只需要判断realPrint为true就可以了。

(0)

相关推荐

  • 基于Silverlight打印的使用详解,是否为微软的Bug问题

    1:新建Silverlight4 应用程序,名称为SLStudy.建好后如下: 2:在SLStudy下新建Silverlight用户控件,Print1.xaml作为要打印的控件. 在Print1.xaml里面添加代码为: 复制代码 代码如下: <Grid x:Name="LayoutRoot" Background="White">      <Button>这是第一个例子,简单的按钮</Button></Grid>

  • 基于python图书馆管理系统设计实例详解

    写完这个项目后,导师说这个你完全可以当作毕业项目使用了,写的很全,很多的都设计考虑周全,但我的脚步绝不止于现在,我想要的是星辰大海!与君共勉! 这个项目不是我的作业, 只是无意中被拉进来了,然后就承担了所有,肝了一周多,终于完成,但这个也算是一个很大的项目了吧,对于我现在来说,写这个项目遇到了很多困难,这是真的,其中涉及到数据库的使用,就遇到了一点瓶颈, 但这不算什么,还是要被我搞定的. 梦想就像这个远处夕阳,终究触手可及! Python项目: 项目前提: 这个项目涉及到的知识点有很多, 知识串

  • 基于tomcat配置文件server.xml详解

    1. 入门示例:虚拟主机提供web服务 该示例通过设置虚拟主机来提供web服务,因为是入门示例,所以设置极其简单,只需修改$CATALINA_HOME/conf/server.xml文件为如下内容即可.其中大部分都采用了默认设置,只是在engine容器中添加了两个Host容器. <?xml version="1.0" encoding="UTF-8"?> <Server port="8005" shutdown="SH

  • 基于JavaScript表单脚本(详解)

    什么是表单? 一个表单有三个基本组成部分: 表单标签:这里面包含了处理表单数据所用CGI程序的URL以及数据提交到服务器的方法. 表单域:包含了文本框.密码框.隐藏域.多行文本框.复选框.单选框.下拉选择框和文件上传框等. 表单按钮:包括提交按钮.复位按钮和一般按钮:用于将数据传送到服务器上的CGI脚本或者取消输入,还可以用表单按钮来控制其他定义了处理脚本的处理工作. JavaScript与表单间的关系:JS最初的应用就是用于分担服务器处理表单的责任,打破依赖服务器的局面,尽管目前web和jav

  • jQuery实现区域打印功能代码详解

    使用CSS控制打印样式,需要设置样式media="print",并且将页面中不需要打印的元素的样式display属性设置为none.如DEMO中,我将页头页脚及其他不需要打印的元素的样式设置如下: <style type="text/css" media="print"> #header,.top_title,#jqprint,#footer,#cssprint h3{display:none} </style> 用jQu

  • 基于AngularJS的简单使用详解

    Angular Js 的初步认识和使用 一: 1.模块化 定义模块和控制器 ng-app="myapp" controller="myctrl" 指定模型 ng-model="" 获取的属性值: ng-bind="属性名"或者{{属性名}} 2.初始化模块(在Script中进行) var myapp1 =angular.module("myapp",[]); 3.定义模块的控制器,并依赖注入, $scope

  • 基于Vue单文件组件详解

    本文将详细介绍Vue单文件组件 概述 在很多 Vue 项目中,使用 Vue.component 来定义全局组件,紧接着用 new Vue({ el: '#container '}) 在每个页面内指定一个容器元素. 这种方式在很多中小规模的项目中运作的很好,在这些项目里 JavaScript 只被用来加强特定的视图.但当在更复杂的项目中,或者前端完全由 JavaScript 驱动的时候,下面这些缺点将变得非常明显: 1.全局定义 (Global definitions) 强制要求每个 compon

  • 基于RestTemplate的使用方法(详解)

    1.postForObject :传入一个业务对象,返回是一个String 调用方: BaseUser baseUser=new BaseUser(); baseUser.setUserid(userid); baseUser.setPass(pass); String postForObject = restTemplate.postForObject(this.getURL()+"/user/login", baseUser, String.class); return postF

  • 基于java Servlet编码/异常处理(详解)

    1. Servlet输出中文 (1)为什么会有乱码? out.println方法在输出时或者表单提交的时候,浏览器会对表单中的中文参数值进行编码; 注:会使用表单所在的页面打开时使用的编码方式进行编码服务器端默认会使用ISO-8859-1进行解码所以会产生乱码 (2)如何解决? 1)post请求:requset.setcharcterencoding(string charset);添加到所有获取参数前并且该方法只支持post方法 2)get请求:修改服务器设置 2. 读取请求参数值 (1)St

  • 基于python时间处理方法(详解)

    在处理数据和进行机器学习的时候,遇到了大量需要处理的时间序列.比如说:数据库读取的str和time的转化,还有time的差值计算.总结一下python的时间处理方面的内容. 一.字符串和时间序列的转化 time.strptime():字符串=>时间序列 time.strftime():时间序列=>字符串 import time start = "2017-01-01" end = "2017-8-12" startTime = time.strptime

随机推荐