WPF之打印与预览

news2024/12/25 1:29:13

目录

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1692762.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【C++】<知识点> 标准和文件的输入输出

目录 一、输入输出操作 1. 相关的类 2. 标准流对象 3. istream类的成员函数 二、流操纵算子 1. 整数流的基数 2. 浮点数精度的流操纵算子 3. 域宽的流操纵算子 4. 其他的流操纵算子 5. 用户自定义流操纵算子 三、文件读写 1. 文本文件的读写 2. 二进制文件的读写 3. 文件读写…

港湾周评|京东图书遭抵制不赢不输

《港湾商业观察》李镭 临近618前夕&#xff0c;数十家出版社抵制京东的消息引发全民关注。一定程上&#xff0c;本就生意冷门或不太赚钱的图书市场&#xff0c;随着这次群起抵制行动&#xff0c;更像是一场行业的反击。 不过&#xff0c;平台有平台的销售策略&#xff0c;毕竟…

给uniapp的扩展组件uni-file-picker设置默认显示的图片

官方给出的代码如下所示&#xff0c;但是按照官网给出的代码图片并没有显示出来。 <template><uni-file-picker readonly :value"fileLists" :imageStyles"imageStyles" file-mediatype"image"></uni-file-picker> </temp…

C#基础一

使用Visual Studio 2022&#xff08;VS2022&#xff09;编写C#控制台程序 1. 安装Visual Studio 2022 确保已安装Visual Studio 2022。如果未安装&#xff0c;请从Visual Studio官网下载并安装。 另一篇文章中已经有详细描述&#xff0c;这里就不在细说了。 VisualStudio2022…

文件自动同步备份-FreeFileSync工具解决硬盘损坏、误操作覆盖导致数据丢失

文件自动同步备份-FreeFileSync工具解决硬盘损坏、误操作覆盖导致数据丢失 文章目录 文件自动同步备份-FreeFileSync工具解决硬盘损坏、误操作覆盖导致数据丢失前言一、FreeFileSync二、使用方法1.用外部存储卡或盘作为异地备份目标盘2.设置同步策略3.设置为windows的自动计划 …

CentOS上升级glibc2.17至glibc2.31

glibc是Linux系统中的重要组件之一。在CentOS中&#xff0c;glibc通常是作为系统的默认C标准库使用的&#xff0c;因为它是许多软件的基础库。在CentOS中&#xff0c;glibc的版本通常与CentOS版本一起发布。因为CentOS通常会优先选择稳定性而不是最新性&#xff0c;所以CentOS使…

前端 CSS 经典:图片边框

前言&#xff1a;有这么一个业务&#xff0c;需要边框随着图片宽度的变化而变化&#xff0c;比如一些聊天的气泡框等。 实现原理&#xff1a;使用 border-image 属性 效果图&#xff1a; 实现代码&#xff1a; <!DOCTYPE html> <html lang"en"><he…

java抽象类,接口,枚举练习题

第一题&#xff1a; 答案&#xff1a; class Animal{//成员变量protected String name;protected int weight;//构造方法public Animal(){this.name"refer";this.weight50;}public Animal(String name,int weight){this.namename;this.weightweight;}//成员方法publ…

基于Android Studio记事本系统

目录 项目介绍 图片展示 运行环境 获取方式 项目介绍 具有登录&#xff0c;注册&#xff0c;记住密码&#xff0c;自动登录的功能&#xff1b; 可以新增记事本&#xff0c;编辑&#xff0c;删除记事本信息&#xff0c;同时可以设置主标题&#xff0c;内容&#xff0c;以及…

【网络】为什么udp协议报头有长度字段,而tcp没有

引言&#xff1a; 在网络通信中&#xff0c;UDP&#xff08;用户数据报协议&#xff09;和TCP&#xff08;传输控制协议&#xff09;是两种常用的传输层协议。它们在设计和功能上有一些不同之处&#xff0c;其中之一就是报头中的长度字段。本文将深入探讨UDP和TCP协议中长度字…

LLM——探索大语言模型在心理学方面的应用研究

1. 概述 心理学经历了多次理论变革&#xff0c;目前人工智能&#xff08;AI&#xff09;和机器学习&#xff0c;特别是大型语言模型&#xff08;LLMs&#xff09;的使用&#xff0c;预示着新研究方向的开启。本文详细探讨了像ChatGPT这样的LLMs如何转变心理学研究。它讨论了LL…

LangChain笔记

很好的LLM知识博客&#xff1a; https://lilianweng.github.io/posts/2023-06-23-agent/ LangChain的prompt hub: https://smith.langchain.com/hub 一. Q&A 1. Q&A os.environ["OPENAI_API_KEY"] “OpenAI的KEY” # 把openai-key放到环境变量里&…

元宇宙虚拟线上会议,可应用于哪些行业和领域?

随着科技的飞速进步和互联网的广泛普及&#xff0c;线上元宇宙会议以其独特的魅力和优势&#xff0c;逐渐崭露头角&#xff0c;积木易搭旗下的元宇宙数字营销平台——视创云展&#xff0c;为线上元宇宙会议提供了全方位的服务&#xff0c;不仅涵盖了场景搭建、数字人互动、在线…

超简单白话文机器学习 - 回归树树剪枝(含算法介绍,公式,源代码实现以及调包实现)

1. 回归树 1.1 算法介绍 大家看到这篇文章时想必已经对树这个概念已经有基础了&#xff0c;如果不是很了解的朋友可以看看笔者的这篇文章&#xff1a; 超简单白话文机器学习-决策树算法全解&#xff08;含算法介绍&#xff0c;公式&#xff0c;源代码实现以及调包实现&#x…

小程序checkbox改成圆形与radio样式保持一致

修改前 修改后 html: <view class"agreement"><checkbox value"{{ isAgreed }}" bind:tap"toggleCheckbox" /><text>我同意室外智能健身房 <text class"link" bind:tap"showUserProtocol">用户协…

【C++】继承(二)深入理解继承:派生类默认成员函数与友元、静态成员的奥秘

目录 派生类的默认成员函数①派生类的构造函数②派生类的拷贝构造函数③派生类的赋值构造④派生类的析构函数 继承与友元继承与静态成员 前言 我们在上一章讲解了: 继承三部曲&#xff0c;本篇基于上次的基础继续深入了解继承的相关知识&#xff0c;欢迎大家和我一起学习继承 派…

Python小游戏——打砖块

文章目录 打砖块游戏项目介绍及实现项目介绍环境配置代码设计思路代码设计详细过程 难点分析源代码代码效果 打砖块游戏项目介绍及实现 项目介绍 打砖块游戏是一款经典的街机游戏&#xff0c;通过控制挡板来反弹小球打碎屏幕上的砖块。该项目使用Python语言和Pygame库进行实现…

牛客NC392 参加会议的最大数目【中等 贪心+小顶堆 Java/Go/PHP 力扣1353】

题目 题目链接&#xff1a; https://www.nowcoder.com/practice/4d3151698e33454f98bce1284e553651 https://leetcode.cn/problems/maximum-number-of-events-that-can-be-attended/description/ 思路 贪心优先级队列Java代码 import java.util.*;public class Solution {/**…

纽曼新品X1000:轻巧便携仅重9.9公斤的1度电应急电源

在户外救援行动和应急设备中&#xff0c;电力供应的稳定性和安全性直接影响到救援工作的效率和成功率。在现代救援工作中&#xff0c;常见的光学声波探测仪、通信联络设备、气象检测仪、生命探测仪、照明设备等装备均需有持续的电力供应&#xff0c;才能保障救援工作的有序开展…

一文带你搞懂DiT(Diffusion Transformer)

节前&#xff0c;我们组织了一场算法岗技术&面试讨论会&#xff0c;邀请了一些互联网大厂朋友、今年参加社招和校招面试的同学。 针对大模型技术趋势、大模型落地项目经验分享、新手如何入门算法岗、该如何准备面试攻略、面试常考点等热门话题进行了深入的讨论。 总结链接…