WPF中打印问题的探讨[转]
转自:http://blog.sina.com.cn/s/blog_624dc0120100ld6m.html
最近在做一个WPF方面的项目,在打印功能实现上费了很大劲。因为我原来是在做Winform方面的项目,接受WPF时感觉还很相似,可仔细往里做下去却发现两者外看相似,实则差异很大,打印就是其中很大的差距。Winform有对应的对话框围绕打印核心类PrintDocument进行操作,而WPF里则是在PrintDialog里进行扩展。WPF简单的打印很简单,几行代码就够,可要实现较大功能时就需要很多的扩展,如分页打印及对打印允许客户有较大的设置自由度时,就很麻烦了。我以我这次的功能实现与大家进行探讨。
常见的打印方式有以下三中:
第一种:对单一控件内容的打印。
private void billtitle_btn_PrintClick(object sender, RoutedEventArgs e)
{
PrintDialog printDialog = new PrintDialog();
if (printDialog.ShowDialog() == true)
{
printDialog.PrintVisual(Mainwindow, "123");
}
}
其中Mainwindow是控件名,也可以是ListView等控件,只要把名称传入即可。很简单,不过不实用,因为这种方法没用自由度,是按系统默认进行打印且只能打印在一页上,数据多了就不行。
第二种:根据PrintDialog进行功能扩展,就可以对打印功能在一定程度上扩展。
/// <summary> //创建一个PrintDocument的实例 //将事件处理函数添加到PrintDocument的PrintPage事件中 //把PrintDialog的Document属性设为上面配置好的PrintDocument的实例 //根据用户的选择,开始打印 //设置打印机开始打印的事件处理函数 在这就可以看出Winform与WPF打印的不同了,在WPF在PrintDocument是一个打印方法。WPF有两种打印途径,一种是第一种方法中的PrintVisual,另一种就是PrintDocument。 第三种:具体步骤如下: 1.PrintDialog This sample illustrates how to create an instance of a simple PrintDialog and then display it. The sample uses both Extensible Application Markup Language (XAML) and procedural code. 这个示例演示了如何进行一个最简单的打印工作,为此需要引入两个dll:ReachFramework.dll和System.Printing。 InvokePrint方法只是显示了一个PrintDialog打印框,并未进行打印工作:
有 PrintableAreaHeight和PrintableAreaWidth两个属性,分别用来表示可打印区域的高和宽。 而对 PrintDialog的设置,可以保存在PrintTicket中,下次再打开PrintDialog,就不必重复进行设置了。
同样,选择使用哪一台打印机的设置,存放在PrintQueue中,下次再打开PrintDialog,也不用再次设置了。
如果要把特定的内容打印输出,则需要调用PrintDialog的PrintVisual方法:
我们能打印的,都是Visual类型的对象,其中UIElement派生于 Visual,从而我们可以打印所有Panel、控件和其它元素,最一般的方法是使用派生于Visual的DrawingVisual类,利用它的 RenderOpen方法生成DrawingContext对象,为其绘制图形,最后使用PrintDialog的PrintVisual方法,输出图形 和文字。 注意到,pDialog.ShowDialog()返回的是可空类型?bool,为此需要使用 GetValueOrDefault将其转为bool值,对于null值也会转为false。 2.EnumerateSubsetOfPrintQueues EnumerateSubsetOfPrintQueues shows how to use the EnumeratedPrintQueueTypes enumeration to get a subset of available print queues. 这个程序演示了如何得到本地和共享的所有打印机列表。为此,需要 使用到EnumeratedPrintQueueTypes枚举中的Local和Shared两个值,组合成一个数组,
作为参数传递到查询方法GetPrintQueues中:
接着就可 以对PrintQueueCollection进行遍历了,获取每一个的PrintQueue名称和所在位置:
|
又构造函数可知,我们需传入一个DataTable,这样可打印的内容、样式等就宽泛多了。DataTable可直接获取,也可自己根据需要构建,我在项目时是根据显示的数据构建一个DataTable。代码如下:
/// <summary>
/// 获取要打印的数据
/// </summary>
private DataTable GetDataTable()
{
DataTable table = new DataTable("Data Table");
// Declare variables for DataColumn and DataRow objects.
DataColumn column;
DataRow row;
// Create new DataColumn, set DataType,
// ColumnName and add to DataTable.
column = new DataColumn();
column.DataType =Type.GetType("System.Int32");
column.ColumnName = "id";
column.Caption = "编号";
column.ReadOnly = true;
column.Unique = true;
// Add the Column to the DataColumnCollection.
table.Columns.Add(column);
// Create second column.
column = new DataColumn();
column.DataType = Type.GetType("System.String");
column.ColumnName = "Name";
column.AutoIncrement = false;
column.Caption = "姓名";
column.ReadOnly = false;
column.Unique = false;
// Add the column to the table.
table.Columns.Add(column);
//Create third column
column = new DataColumn();
column.DataType = Type.GetType("System.String");
column.ColumnName = "Age";
column.AutoIncrement = false;
column.Caption = "年龄";
column.ReadOnly = false;
column.Unique = false;
// Add the column to the table.
table.Columns.Add(column);
//Create forth column
column = new DataColumn();
column.DataType = Type.GetType("System.String");
column.ColumnName = "Pay";
column.AutoIncrement = false;
column.Caption = "工资";
column.ReadOnly = false;
column.Unique = false;
// Add the column to the table.
table.Columns.Add(column);
// Make the ID column the primary key column.
DataColumn[] PrimaryKeyColumns = new DataColumn[1];
PrimaryKeyColumns[0] = table.Columns["id"];
table.PrimaryKey = PrimaryKeyColumns;
// Instantiate the DataSet variable.
//dataSet = new DataSet();
// Add the new DataTable to the DataSet.
//dataSet.Tables.Add(table);
// Create three new DataRow objects and add
// them to the DataTable
for (int i = 0; i <= 60; i++)
{
row = table.NewRow();
row["id"] = i+1;
row["Name"] = "zhangsan " + (i+1).ToString();
row["Age"] = 20 + i;
row["Pay"] = 50 * (i + 1);
table.Rows.Add(row);
}
return table;
}
由此就可以开始打印了:
private void BT_MultiPrint_Click(object sender, RoutedEventArgs e)
{
PrintDialog printDialog = new PrintDialog();
if (printDialog.ShowDialog() == true)
{
DataTable dt = GetDataTable();
try
{
DataPaginator dp = new DataPaginator(dt, new Typeface("SimSun"), 16, 96 * 0.75, new Size(printDialog.PrintableAreaWidth, printDialog.PrintableAreaHeight));
printDialog.PrintDocument(dp, "Test Page");
}
catch
{
MessageBox.Show("无法打印!");
}
}
}
试用后效果还不错。Winform里的打印功能比这强大的多,可以将其使用的控件扩展为WPF里的控件,或进行别的处理。在这就不论述,有兴趣的可以自己去试试。