目录
1,打印设置与管理。
1.1,引入程序集:
1.2,主要管理类介绍:
1.3,应用:
1.4,效果。
1.5,Demo链接。
2,打印。
2.1,主要参与打印的类与属性
2.2,打印可视元素。
2.2,打印文档。
2.3,打印带有页眉页脚的文档。
2.4,打印表格。
2.5,打印到文件。
2.6,使用XpsDocumentWrite打印。
3,打印预览。
4,Demo链接。
1,打印设置与管理。
1.1,引入程序集:
System.Printing.dll,ReachFramework.dll
1.2,主要管理类介绍:
LocalPrintServer:本地打印服务器(应用程序正在其上运行的计算机)用于对其所拥有的众多打印队列进行管理。
PrintQueue:打印队列,封装了打印机管理及作业等功能。可以通过此获取封装的打印机名,打印机端口,打印机状态等信息,以及对打印机的控制(例如打印作业,中止打印作业,取消打印作业)。总之一个PrintQueue控制一个打印机。
PrintTicket::页面打印效果设置,例如纵向,横向打印,双面打印,打印份数,纸张大小 等。
PrintSystemJobInfo:详细定义的打印作业,包含打印作业的文档名,作业名,状态,所有者,页数,大小,提交时间(格林时间)。
1.3,应用:
获取默认的打印队列(即默认的打印机)。
PrintQueue defaultPrintQueue = LocalPrintServer.GetDefaultPrintQueue()
获取所有的打印队列。
LocalPrintServer printServer = new LocalPrintServer();
PrintQueueCollection queues= printServer.GetPrintQueues();
获取打印队列支持的所有纸张类型与大小。
queue.GetPrintCapabilities().PageMediaSizeCapability;
对打印队列进行继续,暂停,取消操作。
private void queueStack_Click(object sender, RoutedEventArgs e)
{
if(e.Source is Button && queuesList.SelectedItem!=null)
{
Button btn = e.Source as Button;
PrintQueue queueTemp = queuesList.SelectedItem as PrintQueue;
// PrintQueue queue= printServer.GetPrintQueue(queueTemp.FullName);
//需要使用PrintQueue构造函数指明权限,否则报拒绝访问异常
PrintQueue queue = new PrintQueue(printServer, queueTemp.FullName,PrintSystemDesiredAccess.AdministratePrinter);
switch (btn.Content.ToString())
{
case "Pause Queue":
queue.Pause();
break;
case "Resume Queue":
queue.Resume();
break;
case "Purge Queue":
//移除所有作业
queue.Purge();
break;
case "Refresh Queue":
queue.Refresh();
break;
case "SettingDefaultPrinter":
string printerName = queue.FullName;
SetDefaultPrinter(printerName);
break;
default:
break;
}
GetPrintQueues();
}
}
获取打印队列的所有作业列表。
//如果抛出NullReferenceException ,就如下通过name重新获取队列后再获取作业列表
server.GetPrintQueue(name).GetPrintJobInfoCollection()
对作业进行暂停,继续,取消,刷新等操作。
private void jobStack_Click(object sender, RoutedEventArgs e)
{
if (e.Source is Button && jobList.SelectedItem != null)
{
Button btn = e.Source as Button;
PrintSystemJobInfo jobInfo = jobList.SelectedItem as PrintSystemJobInfo;
switch (btn.Content.ToString())
{
case "Pause Job":
jobInfo.Pause();
break;
case "Resume Job":
jobInfo.Resume();
break;
case "Purge Job":
//移除所有作业
jobInfo.Cancel();
break;
case "Refresh Job":
jobInfo.Refresh();
break;
default:
break;
}
}
}
设置默认打印机。
/// <summary>
/// 设置默认打印机
/// </summary>
/// <param name="Name"></param>
/// <returns>true为成功,false为失败</returns>
[DllImport("winspool.drv")]
public static extern bool SetDefaultPrinter(String Name); //调用win api将指定名称的打印机设置为默认打印机
1.4,效果。
1.5,Demo链接。
https://download.csdn.net/download/lingxiao16888/89327105?spm=1001.2014.3001.5503
2,打印。
2.1,主要参与打印的类与属性
PrintDialog类:可进行打印作业的封装类。
PrintDialog.PrintQueue:完成本次打印作业的打印机(默认为PC的默认打印机)。
PrintDialog.PrintTicket:完成此次打印作业的纸张大小,打印方向等(默认为PC的默认打印机中的默认打印作业配置)信息。
PrintDialog.PrintableAreaWidth:打印区域的宽度,来源于PrintDialog.PrintTicket.PageMediaSize.Width。
PrintDialog.PrintableAreaHeight:打印区域的高度,来源于PrintDialog.PrintTicket.PageMediaSize.Height。
DocumentPaginator:文档分页器,将内容分割到多页,每页由一个DocumentPage对象表示。DocumentPage实际上是一个封装器,封装Visual对象并添加了一些辅助对象。DocumentPage只增加来了三个属性:Size:页面大小,ContentBox:添加外边距之后内容区域的尺寸,BleedBox:用于显示打印产品相关信息,公司等在纸张上并在页面边界之外。
XpsDocument:用于保存 XPS 文档内容的 System.IO.Packaging.Package。
XpsDocumentWriter:提供用于写入 XPS 文档或打印队列的方法,PrintDialog的打印工作便是通过封装了PrintQueue的XpsDocumentWriter类完成。
2.2,打印可视元素。
<Canvas Background="AliceBlue" x:Name="canvas01">
<Path Panel.ZIndex="1" Stroke="Red" StrokeThickness="2" Fill="SkyBlue" Grid.RowSpan="2" Grid.ColumnSpan="2">
<Path.Data>
<CombinedGeometry GeometryCombineMode="Exclude">
<CombinedGeometry.Geometry1>
<RectangleGeometry Rect="10,10,200,120"></RectangleGeometry>
</CombinedGeometry.Geometry1>
<CombinedGeometry.Geometry2>
<EllipseGeometry Center="110,70" RadiusX="50" RadiusY="40"></EllipseGeometry>
</CombinedGeometry.Geometry2>
</CombinedGeometry>
</Path.Data>
</Path>
<TextBlock Panel.ZIndex="0" FontSize="22" FontWeight="Bold" Canvas.Top="50">春风不度玉门关</TextBlock>
</Canvas>
private void btnPrint_Click(object sender, RoutedEventArgs e)
{
PrintDialog pd = new PrintDialog();
pd.CurrentPageEnabled = true;
pd.SelectedPagesEnabled = true;
pd.UserPageRangeEnabled = true;
if ( pd.ShowDialog()== true)
{
//PrintableAreaWidth,PrintableAreaHeight大小由PrintDialog.PrintTicket提供
//重新布局Grid大小为PrintableAreaWidth,PrintableAreaHeight,其实在这里就是重新设置Canvas的大小
canvas01.Measure(new Size(pd.PrintableAreaWidth, pd.PrintableAreaHeight));
canvas01.Arrange(new Rect(0, 0, pd.PrintableAreaWidth, pd.PrintableAreaHeight));
pd.PrintVisual(canvas01, "可是元素打印");
}
}
注明:PrintDialog. PrintVisual()只考虑指定的元素和其子元素,而不考虑其父元素的细节,所以可以对指定元素的父元素采取隐藏的操作,而不影响打印效果。
效果:
2.2,打印文档。
此xaml后同,不再赘述
<FlowDocumentScrollViewer x:Name="fsv01" >
<FlowDocument >
<FlowDocument.Resources>
<Style TargetType="Paragraph">
<Setter Property="TextIndent" Value="32"></Setter>
</Style>
</FlowDocument.Resources>
<Paragraph FontWeight="Bold" FontSize="16" TextAlignment="Center">
荷塘月色
<Run FontSize="12" FontWeight="Normal" xml:space="preserve"> 朱自清</Run>
</Paragraph>
<Paragraph TextIndent="32">
这几天心里颇不宁静。今晚在院子里坐着乘凉,忽然想起日日走过的荷塘,在这满月的光里,总该另有一番样子吧。月亮渐渐地升高了,墙外马路上孩子们的欢笑,已经听不见了;妻在屋里拍着闰儿⑴,迷迷糊糊地哼着眠歌。我悄悄地披了大衫,带上门出去。
</Paragraph>
<Paragraph>
沿着荷塘,是一条曲折的小煤屑路。这是一条幽僻的路;白天也少人走,夜晚更加寂寞。荷塘四面,长着许多树,蓊蓊郁郁⑵的。路的一旁,是些杨柳,和一些不知道名字的树。没有月光的晚上,这路上阴森森的,有些怕人。今晚却很好,虽然月光也还是淡淡的。
</Paragraph>
<Paragraph>
路上只我一个人,背着手踱⑶着。这一片天地好像是我的;我也像超出了平常的自己,到了另一个世界里。我爱热闹,也爱冷静;爱群居,也爱独处。像今晚上,一个人在这苍茫的月下,什么都可以想,什么都可以不想,便觉是个自由的人。白天里一定要做的事,一定要说的话,现在都可不理。这是独处的妙处,我且受用这无边的荷香月色好了。
</Paragraph>
<Paragraph>
曲曲折折的荷塘上面,弥望⑷的是田田⑸的叶子。叶子出水很高,像亭亭的舞女的裙。层层的叶子中间,零星地点缀着些白花,有袅娜⑹地开着的,有羞涩地打着朵儿的;正如一粒粒的明珠,又如碧天里的星星,又如刚出浴的美人。微风过处,送来缕缕清香,仿佛远处高楼上渺茫的歌声似的。这时候叶子与花也有一丝的颤动,像闪电般,霎时传过荷塘的那边去了。叶子本是肩并肩密密地挨着,这便宛然有了一道凝碧的波痕。叶子底下是脉脉⑺的流水,遮住了,不能见一些颜色;而叶子却更见风致⑻了。
</Paragraph>
<Paragraph>
月光如流水一般,静静地泻在这一片叶子和花上。薄薄的青雾浮起在荷塘里。叶子和花仿佛在牛乳中洗过一样;又像笼着轻纱的梦。虽然是满月,天上却有一层淡淡的云,所以不能朗照;但我以为这恰是到了好处——酣眠固不可少,小睡也别有风味的。月光是隔了树照过来的,高处丛生的灌木,落下参差的斑驳的黑影,峭楞楞如鬼一般;弯弯的杨柳的稀疏的倩影,却又像是画在荷叶上。塘中的月色并不均匀;但光与影有着和谐的旋律,如梵婀玲⑼上奏着的名曲。
</Paragraph>
<Paragraph>
荷塘的四面,远远近近,高高低低都是树,而杨柳最多。这些树将一片荷塘重重围住;只在小路一旁,漏着几段空隙,像是特为月光留下的。树色一例是阴阴的,乍看像一团烟雾;但杨柳的丰姿⑽,便在烟雾里也辨得出。树梢上隐隐约约的是一带远山,只有些大意罢了。树缝里也漏着一两点路灯光,没精打采的,是渴睡⑾人的眼。这时候最热闹的,要数树上的蝉声与水里的蛙声;但热闹是它们的,我什么也没有。
</Paragraph>
<Paragraph>
忽然想起采莲的事情来了。采莲是江南的旧俗,似乎很早就有,而六朝时为盛;从诗歌里可以约略知道。采莲的是少年的女子,她们是荡着小船,唱着艳歌去的。采莲人不用说很多,还有看采莲的人。那是一个热闹的季节,也是一个风流的季节。梁元帝《采莲赋》里说得好:
</Paragraph>
<Paragraph>
于是妖童媛女⑿,荡舟心许;鷁首⒀徐回,兼传羽杯⒁;棹⒂将移而藻挂,船欲动而萍开。尔其纤腰束素⒃,迁延顾步⒄;夏始春余,叶嫩花初,恐沾裳而浅笑,畏倾船而敛裾⒅。
</Paragraph>
<Paragraph>
可见当时嬉游的光景了。这真是有趣的事,可惜我们现在早已无福消受了。
</Paragraph>
<Paragraph>
于是又记起,《西洲曲》里的句子:
</Paragraph>
<Paragraph>
采莲南塘秋,莲花过人头;低头弄莲子,莲子清如水。
</Paragraph>
<Paragraph>
今晚若有采莲人,这儿的莲花也算得“过人头”了;只不见一些流水的影子,是不行的。这令我到底惦着江南了。——这样想着,猛一抬头,不觉已是自己的门前;轻轻地推门进去,什么声息也没有,妻已睡熟好久了。
</Paragraph>
<Paragraph>
一九二七年七月,北京清华园。
</Paragraph>
</FlowDocument>
</FlowDocumentScrollViewer>
private void btnPrint_Click(object sender, RoutedEventArgs e)
{
PrintDialog pd = new PrintDialog();
FlowDocument document = fsv01.Document;
document.PagePadding = new Thickness(30);
double pageWidth = document.PageWidth;
double pageHeight = document.PageHeight;
document.PageWidth = pd.PrintableAreaWidth;
document.PageHeight = pd.PrintableAreaHeight;
document.ColumnWidth = document.PageWidth;
document.PageHeight = pd.PrintableAreaHeight;
document.PageWidth = pd.PrintableAreaWidth;
//获取分页器,分页器接口中的分页器属性是显示实现,所以将flowDocumen 转换为对应的接口
DocumentPaginator paginator = ((IDocumentPaginatorSource)document).DocumentPaginator;
if (pd.ShowDialog() == true)
{
pd.PrintDocument(paginator, "荷塘月色");
}
document.PageWidth = pageWidth;
document.PageHeight = pageHeight;
}
效果(这里以Xps打印机打印效果呈现,后同,不再赘述):
2.3,打印带有页眉页脚的文档。
PrintDialog未提供包含页眉页脚的打印分页方法,这里通过派生抽象类DocumentPaginator的自定义类实现。
/// <summary>
/// 可添加页眉页脚的流文档分页器(专用于流文档的分页器)
/// </summary>
class CustomFlowDocumentPaginator : DocumentPaginator
{
DocumentPaginator paginator;
FlowDocument curFlowDocument;
FrameworkElement header;
FrameworkElement footer;
/// <summary>
/// 可添加页眉页脚的分页器
/// </summary>
/// <param name="flowDocument">需要添加页眉页脚的流文档</param>
/// <param name="header">页眉</param>
/// <param name="footer">页脚</param>
public CustomFlowDocumentPaginator(FlowDocument flowDocument, FrameworkElement header = null, FrameworkElement footer = null)
{
paginator = (flowDocument as IDocumentPaginatorSource).DocumentPaginator;
curFlowDocument = flowDocument;
if (header != null)
{
this.header = header;
this.header.Width = curFlowDocument.PageWidth;
this.header.Height = flowDocument.PagePadding.Top;
}
if (footer != null)
{
this.footer = footer;
this.footer.Width = curFlowDocument.PageWidth;
this.footer.Height = flowDocument.PagePadding.Bottom;
}
PageSize = new Size(flowDocument.PageWidth, flowDocument.PageHeight);
}
//通过该属性确定GetPage()执行次数
public override bool IsPageCountValid
{
get
{
return paginator.IsPageCountValid;
}
}
public override int PageCount
{
get
{
return paginator.PageCount;
}
}
public override Size PageSize
{
get
{
return paginator.PageSize;
}
set
{
paginator.PageSize = value;
}
}
public override IDocumentPaginatorSource Source
{
get
{
return paginator.Source;
}
}
public override DocumentPage GetPage(int pageNumber)
{
//获取当前页
DocumentPage curPage = paginator.GetPage(pageNumber);
Visual visual = curPage.Visual;
ContainerVisual container = new ContainerVisual();
//注意在ContainerVirsual中添加可视元素时,可视元素需要与原有的逻辑容器断开连接否则报异常
//简单的将控件以Visual形式添加到其中并不能显示
container.Children.Add(visual);
if (header != null)
{
DrawingVisual dv = new DrawingVisual();
using (DrawingContext context = dv.RenderOpen())
{
context.DrawRectangle(new VisualBrush(header), null, new Rect(0, 0, header.Width, header.Height));
}
container.Children.Add(dv);
}
if (footer != null)
{
DrawingVisual dv = new DrawingVisual();
using (DrawingContext context = dv.RenderOpen())
{
context.DrawRectangle(new VisualBrush(footer), null, new Rect(0, PageSize.Height - footer.Height, footer.Width, footer.Height));
}
container.Children.Add(dv);
}
//根据此进行布局
DocumentPage newPage = new DocumentPage(container, paginator.PageSize, new Rect(0, 0, paginator.PageSize.Width, paginator.PageSize.Height), new Rect(curFlowDocument.PagePadding.Left, curFlowDocument.PagePadding.Top, curFlowDocument.PageWidth - curFlowDocument.PagePadding.Left - curFlowDocument.PagePadding.Right, curFlowDocument.PageHeight - curFlowDocument.PagePadding.Top - curFlowDocument.PagePadding.Bottom));
return newPage;
}
}
定义页眉的xaml文件。
<Border BorderBrush="Transparent" BorderThickness="1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" Height="88.5" Width="446">
<DockPanel Margin="0,0,0,20" >
<TextBlock DockPanel.Dock="Right" Margin="20"><Run Text="流文档打印"/></TextBlock>
<Image Source="/Img/1.png" DockPanel.Dock="Left" Width="100" VerticalAlignment="Center"/>
<TextBlock Text="页眉" FontSize="20" FontFamily="华文行楷" VerticalAlignment="Center" HorizontalAlignment="Center"/>
</DockPanel>
</Border>
UI效果
/// <summary>
///流文档打印帮助类(专用于流文档的打印帮助类)
/// </summary>
public class WPFPrintHelper
{
PrintDialog pd;
FlowDocument fd;
FlowDocumentScrollViewer flowDocumentViewer;
FlowDocumentReader flowDocumentReader;
Thickness padding;
double pageWidth;
double pageHeight;
TableDocumentPaginator tablePaginator;
public event EventHandler<string> PrintCompleted;
public WPFPrintHelper(PrintDialog pd, FlowDocument fd, Thickness padding)
{
if (fd == null)
throw new ArgumentNullException("流文档不能为null!");
this.pd = pd;
this.fd = fd;
if (fd.Parent != null)
{
if (fd.Parent is FlowDocumentScrollViewer)
{
flowDocumentViewer = fd.Parent as FlowDocumentScrollViewer;
flowDocumentViewer.Document = null;
}
if (fd.Parent is FlowDocumentReader)
{
flowDocumentReader = fd.Parent as FlowDocumentReader;
flowDocumentReader.Document = null;
}
}
this.padding = fd.PagePadding;
fd.PagePadding = padding;
pageWidth = fd.PageWidth;
pageHeight = fd.PageHeight;
fd.PageWidth = pd.PrintableAreaWidth;
fd.PageHeight = pd.PrintableAreaHeight;
fd.ColumnWidth = fd.PageWidth;
}
/// <summary>
/// 用于表格打印的构造函数
/// </summary>
/// <param name="pd"></param>
/// <param name="dt">需要进行打印的表格</param>
/// <param name="padding">边距</param>
/// <param name="fields">表格中需要打印的字段</param>
public WPFPrintHelper(PrintDialog pd, DataTable dt, Thickness padding, List<FieldSetting> fields)
{
tablePaginator = new TableDocumentPaginator(dt, new Size(pd.PrintableAreaWidth, pd.PrintableAreaHeight), fields);
tablePaginator.Margin = padding;
this.pd = pd;
}
/// <summary>
/// 列头字体(仅用于表格打印)
/// </summary>
public Typeface ColumnHeaderTypeFace
{
get
{
return tablePaginator.ColumnHeaderTypeFace;
}
set
{
tablePaginator.ColumnHeaderTypeFace = value;
}
}
/// <summary>
/// 单元格字体(仅用于打印表格)
/// </summary>
public Typeface ContentTypeFace
{
get
{
return tablePaginator.ContentTypeFace;
}
set
{
tablePaginator.ContentTypeFace = value;
}
}
/// <summary>
/// 列头高度(仅用于打印表格)
/// </summary>
public double HeaderHeight
{
get
{
return tablePaginator.HeaderHeight;
}
set
{
tablePaginator.HeaderHeight = value;
}
}
/// <summary>
/// 行高(仅用于打印表格)
/// </summary>
public double RowHeight
{
get
{
return tablePaginator.RowHeight;
}
set
{
tablePaginator.RowHeight = value;
}
}
/// <summary>
/// 列标题字体大小(仅用于打印表格)
/// </summary>
public double ColumnHeaderFontSize
{
get { return tablePaginator.ColumnHeaderFontSize; }
set { tablePaginator.ColumnHeaderFontSize = value; }
}
/// <summary>
/// 单元格字体大小(仅用于打印表格)
/// </summary>
public double ConentFontSize
{
get
{
return tablePaginator.ConentFontSize;
}
set
{
tablePaginator.ConentFontSize = value;
}
}
/// <summary>
/// 页眉
/// </summary>
public FrameworkElement Header { get; set; }
/// <summary>
/// 页脚
/// </summary>
public FrameworkElement Footer { get; set; }
/// <summary>
/// 对流文档进行打印
/// </summary>
/// <param name="description">打印作业说明</param>
public void PrintFlowDocument(string description)
{
string msg =description+ " 打印完成!";
try
{
CustomFlowDocumentPaginator paginator = new CustomFlowDocumentPaginator(fd, Header, Footer);
//var num = pd.MaxPage;
pd.PrintDocument(paginator, description);
if (flowDocumentReader != null)
{
fd.PagePadding = padding;
fd.PageWidth = pageWidth;
fd.PageHeight = pageWidth;
flowDocumentReader.Document = fd;
}
if (flowDocumentViewer != null)
{
fd.PagePadding = padding;
fd.PageWidth = pageWidth;
fd.PageHeight = pageWidth;
flowDocumentViewer.Document = fd;
}
}
catch (Exception ex)
{
msg = ex.Message;
}
finally
{
PrintCompleted?.Invoke(this, msg);
}
}
/// <summary>
/// 打印表格
/// </summary>
/// <param name="description">打印说明</param>
public void PrintTable(string description)
{
tablePaginator.Header = this.Header;
tablePaginator.Footer = this.Footer;
pd.PrintDocument(tablePaginator, description);
PrintCompleted?.Invoke(this, description+" 打印完成");
}
}
注明:因FlowDocument尚位于FlowDocumentScrollViewer的 VirtualTree中,如果需要将其添加到另外的可视元素中需要将其从其现有父元素中解构,解构的方法是将FlowDocumentScrollViewer.Document=null。
private void btnHeaderPrint_Click(object sender, RoutedEventArgs e)
{
PrintDialog pd = new PrintDialog();
FlowDocument document = fsv01.Document;
Border header;
using (System.IO.FileStream fs = new System.IO.FileStream("../../header.xaml", System.IO.FileMode.Open))
{
header = XamlReader.Load(fs) as Border;
}
Border footer = new Border() { Background = Brushes.AliceBlue };
TextBlock tb2 = new TextBlock() { Text = "页脚" };
tb2.Foreground = Brushes.Red;
tb2.FontSize = 16;
footer.Child = tb2;
if (pd.ShowDialog() == true)
{
Common.WPFPrintHelper printer = new WPFPrintHelper(pd, document, new Thickness(50, 100, 50, 50));
printer.Header = header;
printer.Footer = footer;
printer.PrintCompleted += Printer_PrintCompleted;
// pd.PrintQueue = new PrintServer().GetPrintQueue("HP 910");//通过此设置进行作业的打印机
printer.PrintFlowDocument("荷塘月色");
}
}
打印效果
2.4,打印表格。
PrintDialog未提供表格打印分页方法,这里通过派生抽象类DocumentPaginator的自定义类实现。
/// <summary>
/// 表格分页器
/// </summary>
class TableDocumentPaginator : DocumentPaginator
{
Size pageSize;
DataTable dt;
List<FieldSetting> fields;
Point originPoint;
public TableDocumentPaginator(DataTable dt, Size printPageSize, List<FieldSetting> fields)
{
this.dt = dt;
pageSize = new Size(printPageSize.Width, printPageSize.Height);
this.fields = fields;
}
Thickness margin = new Thickness(100);
/// <summary>
/// 页边距
/// </summary>
public Thickness Margin
{
get
{
return margin;
}
set
{
margin = value;
}
}
Typeface columnHeaderTypeFace = new Typeface(new FontFamily("仿宋"), FontStyles.Normal, FontWeights.Normal, FontStretches.Normal);
/// <summary>
/// 列头字体
/// </summary>
public Typeface ColumnHeaderTypeFace
{
get
{
return columnHeaderTypeFace;
}
set
{
columnHeaderTypeFace = value;
}
}
Typeface contentTypeFace = new Typeface(new FontFamily("仿宋"), FontStyles.Normal, FontWeights.Normal, FontStretches.Normal);
/// <summary>
/// 内容字体
/// </summary>
public Typeface ContentTypeFace
{
get
{
return contentTypeFace;
}
set
{
contentTypeFace = value;
}
}
double headerHeight = 40;
/// <summary>
/// 列头高度
/// </summary>
public double HeaderHeight
{
get
{
return headerHeight;
}
set
{
headerHeight = value;
}
}
double rowHeight;
public double RowHeight
{
get
{
return GetFormattedText("Row", ContentTypeFace, ConentFontSize).Height * 3;
}
set
{
rowHeight = value;
}
}
/// <summary>
/// 列标题字体大小
/// </summary>
public double ColumnHeaderFontSize { get; set; } = 14;
/// <summary>
/// 内容字体大小
/// </summary>
public double ConentFontSize { get; set; } = 12;
/// <summary>
/// 页头
/// </summary>
public FrameworkElement Header { get; set; }
/// <summary>
/// 页脚
/// </summary>
public FrameworkElement Footer { get; set; }
bool isPageCountValid = false;
/// <summary>
/// 指定PageCount页面数量是否有效,后面将根据此决定调用GetPage()次数
/// </summary>
public override bool IsPageCountValid
{
get
{
return isPageCountValid;
}
}
int pageCount;
/// <summary>
/// 在IsPageCountValid=true时,PageCount将确定循环的次数
/// </summary>
public override int PageCount
{
get
{
return pageCount;
}
}
/// <summary>
/// 是否有边框
/// </summary>
public bool HasBorder { get; set; } = true;
public override Size PageSize
{
get
{
return pageSize;
}
set
{
pageSize = value;
}
}
public override IDocumentPaginatorSource Source
{
get
{
return null;
}
}
int curRowNum = 0;
public override DocumentPage GetPage(int pageNumber)
{
originPoint = new Point(Margin.Left, Margin.Top);
//打印列表头
DrawingVisual visual = new DrawingVisual();
using (DrawingContext context = visual.RenderOpen())
{
if (!HasBorder)
{
//context.DrawRectangle(null, new Pen(Brushes.Black, 1), new Rect(Margin.Left, margin.Top, PageSize.Width - Margin.Left - Margin.Right, PageSize.Height - Margin.Top - Margin.Bottom));
}
double size_x = 0;
double size_y = GetFormattedText("H", ColumnHeaderTypeFace, ColumnHeaderFontSize).Height;
Point printPoint = new Point(originPoint.X, originPoint.Y + (HeaderHeight - size_y) / 2);
double curWidth = 0;
foreach (var item in fields)
{
FormattedText txt = GetFormattedText(item.FieldName, ColumnHeaderTypeFace, ColumnHeaderFontSize);
size_x = txt.Width;
switch (item.TextAlignment)
{
case TextAlignment.Left:
printPoint.X = originPoint.X + curWidth + 2;
break;
case TextAlignment.Right:
printPoint.X = originPoint.X + curWidth + item.ColumnWidth - size_x - 2;
break;
case TextAlignment.Center:
printPoint.X = originPoint.X + curWidth + (item.ColumnWidth - size_x) / 2;
break;
default:
break;
}
curWidth += item.ColumnWidth;
context.DrawText(txt, printPoint);
if (HasBorder)
{
context.DrawRectangle(null, new Pen(Brushes.Black, 1), new Rect(originPoint.X + curWidth - item.ColumnWidth, originPoint.Y, item.ColumnWidth, HeaderHeight));
}
}
originPoint.Y = originPoint.Y + HeaderHeight;
originPoint.X = Margin.Left;
int num = 0;
size_y = GetFormattedText("Row", contentTypeFace, ConentFontSize).Height;
//打印内容
for (int i = curRowNum; i < dt.Rows.Count; i++)
{
if ((originPoint.Y + RowHeight > PageSize.Height - Margin.Bottom))
{
//一页打完
break;
}
curWidth = 0;
//每一列
foreach (var item in fields)
{
string fieldVal = dt.Rows[i][item.FieldName].ToString();
FormattedText txt = GetFormattedText(fieldVal, ContentTypeFace, ConentFontSize);
txt.MaxTextWidth = item.ColumnWidth - 4;
size_x = txt.Width;
size_y = txt.Height;
printPoint = new Point(originPoint.X, originPoint.Y + (RowHeight - size_y) / 2);
switch (item.TextAlignment)
{
case TextAlignment.Left:
printPoint.X = originPoint.X + curWidth + 2;
break;
case TextAlignment.Right:
printPoint.X = originPoint.X + curWidth + item.ColumnWidth - size_x - 2;
break;
case TextAlignment.Center:
printPoint.X = originPoint.X + curWidth + (item.ColumnWidth - size_x) / 2;
break;
default:
break;
}
context.DrawText(txt, printPoint);
curWidth += item.ColumnWidth;
if (HasBorder)
{
context.DrawRectangle(null, new Pen(Brushes.Black, 1), new Rect(originPoint.X + curWidth - item.ColumnWidth, originPoint.Y, item.ColumnWidth, RowHeight));
}
}
if (size_y > RowHeight)
{
originPoint.Y += size_y + 5;
}
else
{
originPoint.Y += RowHeight;
}
originPoint.X = Margin.Left;
num++;
curRowNum++;
}
}
pageCount++;
//打印完成
if (curRowNum == dt.Rows.Count)
{
isPageCountValid = true;
}
if (Header != null)
{
Header.Width = PageSize.Width;
Header.Height = Margin.Top;
DrawingVisual dv = new DrawingVisual();
using (DrawingContext context = dv.RenderOpen())
{
context.DrawRectangle(new VisualBrush(Header), null, new Rect(0, 0, Header.Width, Header.Height));
}
visual.Children.Add(dv);
}
if (Footer != null)
{
Footer.Width = PageSize.Width;
Footer.Height = Margin.Bottom;
DrawingVisual dv = new DrawingVisual();
using (DrawingContext context = dv.RenderOpen())
{
context.DrawRectangle(new VisualBrush(Footer), null, new Rect(0, PageSize.Height - Footer.Height, Footer.Width, Footer.Height));
}
visual.Children.Add(dv);
}
return new DocumentPage(visual, PageSize, new Rect(0, 0, PageSize.Width, PageSize.Height), new Rect(Margin.Left, margin.Top, PageSize.Width - Margin.Left - Margin.Right, PageSize.Height - Margin.Top - Margin.Bottom));
}
FormattedText GetFormattedText(string txt, Typeface typeface, double fontSize)
{
return new FormattedText(txt, System.Globalization.CultureInfo.CurrentCulture, FlowDirection.LeftToRight, typeface, fontSize, Brushes.Black);
}
}
public class FieldSetting
{
/// <summary>
/// 字段名
/// </summary>
public string FieldName
{
get; set;
}
/// <summary>
/// 字段对齐方式
/// </summary>
public TextAlignment TextAlignment { get; set; } = TextAlignment.Center;
public double ColumnWidth { get; set; } = 120;
// public Typeface ColumnTypeface { get; set; } = new Typeface(new FontFamily("仿宋"), FontStyles.Normal, FontWeights.Normal, FontStretches.Normal);
}
private void btnTablePrint_Click(object sender, RoutedEventArgs e)
{
DataSet set = new DataSet();
//从xml文件中读取示例数据
set.ReadXml("store.xml");
//从xml架构文件中读取store.xml的架构
set.ReadXmlSchema("storeSchema.xsd");
//页眉
Border header;
using (System.IO.FileStream fs = new System.IO.FileStream("../../header.xaml", System.IO.FileMode.Open))
{
header = XamlReader.Load(fs) as Border;
}
//页脚
Border footer = new Border() { Background = Brushes.AliceBlue };
TextBlock tb2 = new TextBlock() { Text = "samsung" };
tb2.Foreground = Brushes.Red;
tb2.FontSize = 16;
footer.Child = tb2;
PrintDialog pd = new PrintDialog();
//数据表中需要打印的列
List<FieldSetting> fields = new List<FieldSetting>
{
new FieldSetting { FieldName="ModelNumber" , ColumnWidth=140},
new FieldSetting {FieldName="ModelName" , TextAlignment= TextAlignment.Left, ColumnWidth=140},
new FieldSetting {FieldName ="ProductImage" },
new FieldSetting { FieldName="UnitCost" }
};
WPFPrintHelper printer = new WPFPrintHelper(pd, set.Tables[0], new Thickness(50, 100, 50, 50), fields);
printer.PrintCompleted += Printer_PrintCompleted;
printer.ColumnHeaderFontSize = 16;
printer.Header = header;
printer.Footer = footer;
printer.ColumnHeaderTypeFace = new Typeface(new FontFamily("微软雅黑"), FontStyles.Normal, FontWeights.Normal, FontStretches.Normal);
printer.PrintTable("打印表格");
}
打印效果:
2.5,打印到文件。
使用XPSDocumentWrite将内容打印到Xps文件。
private void btnPrintFile_Click(object sender, RoutedEventArgs e)
{
SaveFileDialog sfd = new SaveFileDialog();
sfd.Filter = "xps文件|*.xps";
if (sfd.ShowDialog() == true)
{
FlowDocument fd = fsv01.Document;
fd.ColumnWidth = LocalPrintServer.GetDefaultPrintQueue().DefaultPrintTicket.PageMediaSize.Width.Value;
XpsDocument document = new XpsDocument(sfd.FileName, System.IO.FileAccess.ReadWrite);
XpsDocumentWriter writer = XpsDocument.CreateXpsDocumentWriter(document);
writer.Write((fd as IDocumentPaginatorSource).DocumentPaginator);
document.Close();
}
}
2.6,使用XpsDocumentWrite打印。
private void btnPrint2_Click(object sender, RoutedEventArgs e)
{
FlowDocument fd = fsv01.Document;
fd.ColumnWidth = LocalPrintServer.GetDefaultPrintQueue().DefaultPrintTicket.PageMediaSize.Width.Value;
//从打印队列上获取xpsDocumentWriter
XpsDocumentWriter writer = PrintQueue.CreateXpsDocumentWriter(LocalPrintServer.GetDefaultPrintQueue());
writer.WritingCompleted += Writer_WritingCompleted;
writer.WriteAsync((fd as IDocumentPaginatorSource).DocumentPaginator);
}
private void Writer_WritingCompleted(object sender, System.Windows.Documents.Serialization.WritingCompletedEventArgs e)
{
MessageBox.Show("保存完成");
}
事实上PrintDialog的打印工作也是委托给XpsDocumentWrite完成。
3,打印预览。
使用固定文档容器(DocumentViewer)展现文档预览效果。
<Window x:Class="文档打印.PreView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:文档打印"
mc:Ignorable="d"
Title="PreView" Height="500" Width="500" WindowState="Maximized">
<Grid>
<DocumentViewer x:Name="viewer"></DocumentViewer>
</Grid>
</Window>
private void btnPrePrint_Click(object sender, RoutedEventArgs e)
{
if (System.IO.Directory.Exists("temp"))
{
if(System.IO.Directory.GetFileSystemEntries("temp").Length > 0)
{
System.IO.Directory.Delete("temp", true);
}
}
if (!System.IO.Directory.Exists("temp"))
{
System.IO.Directory.CreateDirectory("temp");
}
string tempFilePath = string.Format("temp/{0}.xps", Guid.NewGuid());
XpsDocument document = new XpsDocument(tempFilePath, System.IO.FileAccess.ReadWrite);
XpsDocumentWriter writer = XpsDocument.CreateXpsDocumentWriter(document);
FlowDocument fd = fsv01.Document;
fsv01.Document = null;
fd.ColumnWidth = LocalPrintServer.GetDefaultPrintQueue().DefaultPrintTicket.PageMediaSize.Width.Value;
DocumentPaginator paginator = (fd as IDocumentPaginatorSource).DocumentPaginator;
writer.WritingCompleted += Writer_WritingCompleted;
writer.Write(paginator);
PreView win = new PreView(document.GetFixedDocumentSequence());
win.ShowDialog();
document.Close();
fsv01.Document = fd;
//删除临时文档
System.IO.File.Delete(tempFilePath);
}
注明: DocumentViewer.Document:类型为IDocumentPaginatorSource,虽然FlowDocument实现IDocumentPaginatorSource,但是DocumentViewer 仅支持 FixedDocument 或 FixedDocumentSequence 文档,所以这里必须通过XpsDocument将流文档转为固定文档。
效果:
4,Demo链接。
https://download.csdn.net/download/lingxiao16888/89327115?spm=1001.2014.3001.5503