简体   繁体   English

WPF 固定文档分页

[英]WPF FixedDocument pagination

How do I get FixedDocument to automatically paginate?如何让 FixedDocument 自动分页? I have the following code that I can use to put prettified Panel into a DocViewer.我有以下代码可用于将美化面板放入 DocViewer。 The problem occurs when the Panel extends past a single page.当面板延伸超过单个页面时会出现问题。 Right now, we simply clip.现在,我们只是剪辑。 Basically, I want to create a fairly generic way to print what the user is viewing.基本上,我想创建一种相当通用的方式来打印用户正在查看的内容。 Is my approach reasonable?我的做法合理吗?

    public void CreateReport(Panel details)
    {
        FixedDocument fixedDoc = new FixedDocument();
        PageContent pageContent = new PageContent();
        FixedPage fixedPage = new FixedPage();

        fixedPage.DataContext = this.DataContext;
        fixedPage.Margin = new Thickness(10);

        fixedPage.Children.Add(details);
        ((System.Windows.Markup.IAddChild)pageContent).AddChild(fixedPage);
        fixedDoc.Pages.Add(pageContent);

        // This makes the array of controls invisibile, then climbs the details structure
        // and makes the controls within details appropriate for the DocumentViewwer (i.e. TextBoxes are
        // non-editable, no borders, no scroll bars, etc).
        prePrintPrepare(details, fixedPage, new FrameworkElement[] { controlToMakeInvisible });

        _dv = new DocViewer();
        _dv.documentViewer1.Document = fixedDoc;
        _dv.Show();
    }

I hate answering my own question, but, the following gave me a reasonable solution: http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/bd89e0d2-73df-4b9b-9210-b8be83ff29d6/我讨厌回答我自己的问题,但是,以下给了我一个合理的解决方案: http : //social.msdn.microsoft.com/Forums/en-US/wpf/thread/bd89e0d2-73df-4b9b-9210-b8be83ff29d6/

Scott斯科特

public static class PrintHelper
{
    public static FixedDocument GetFixedDocument(FrameworkElement toPrint, PrintDialog printDialog)
    {
        PrintCapabilities capabilities = printDialog.PrintQueue.GetPrintCapabilities(printDialog.PrintTicket);
        Size pageSize = new Size(printDialog.PrintableAreaWidth, printDialog.PrintableAreaHeight);
        Size visibleSize = new Size(capabilities.PageImageableArea.ExtentWidth, capabilities.PageImageableArea.ExtentHeight);
        FixedDocument fixedDoc = new FixedDocument();

        // If the toPrint visual is not displayed on screen we neeed to measure and arrange it.
        toPrint.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
        toPrint.Arrange(new Rect(new Point(0, 0), toPrint.DesiredSize));

        Size size = toPrint.DesiredSize;

        // Will assume for simplicity the control fits horizontally on the page.
        double yOffset = 0;
        while (yOffset < size.Height)
        {
            VisualBrush vb = new VisualBrush(toPrint);
            vb.Stretch = Stretch.None;
            vb.AlignmentX = AlignmentX.Left;
            vb.AlignmentY = AlignmentY.Top;
            vb.ViewboxUnits = BrushMappingMode.Absolute;
            vb.TileMode = TileMode.None;
            vb.Viewbox = new Rect(0, yOffset, visibleSize.Width, visibleSize.Height);

            PageContent pageContent = new PageContent();
            FixedPage page = new FixedPage();
            ((IAddChild)pageContent).AddChild(page);
            fixedDoc.Pages.Add(pageContent);
            page.Width = pageSize.Width;
            page.Height = pageSize.Height;

            Canvas canvas = new Canvas();
            FixedPage.SetLeft(canvas, capabilities.PageImageableArea.OriginWidth);
            FixedPage.SetTop(canvas, capabilities.PageImageableArea.OriginHeight);
            canvas.Width = visibleSize.Width;
            canvas.Height = visibleSize.Height;
            canvas.Background = vb;
            page.Children.Add(canvas);

            yOffset += visibleSize.Height;
        }
        return fixedDoc;
    }

    public static void ShowPrintPreview(FixedDocument fixedDoc)
    {
        Window wnd = new Window();
        DocumentViewer viewer = new DocumentViewer();
        viewer.Document = fixedDoc;
        wnd.Content = viewer;
        wnd.ShowDialog();
    }
}

For those who are interested in a different and maybe more "advanced" solution, go ahead and check out my repository on GitHub where I demonstrate how to create XAML reports, paginate them, then produce a printable FixedDocument from them.对于那些对不同的、可能更“高级”的解决方案感兴趣的人,请继续查看在 GitHub 上的存储库,在那里我演示了如何创建 XAML 报告、对它们进行分页,然后从中生成可打印的 FixedDocument。

The magic happens in Paginator.cs where the code goes through all the custom attached properties and uses them to determine where to set page number, which elements to show only on first page, and more...神奇发生在Paginator.cs 中,其中代码遍历所有自定义附加属性并使用它们来确定在哪里设置页码,哪些元素仅显示在第一页上,等等......

All reports are defined as plain XAML user controls, and are converted to fixed pages after pagination is done.所有报告都定义为普通 XAML 用户控件,并在分页完成后转换为固定页面。 The benefit is that you can define your document/report in pure XAML, add a few attached properties, and the paginator code takes care of the rest.好处是您可以在纯 XAML 中定义您的文档/报告,添加一些附加属性,分页器代码负责其余的工作。

It's been a long time since the question has been answered.自从问题得到回答以来已经很长时间了。
I tried Doo Dah's answer, but the problem was that it doesn't take care of the page paddings of a flowdocument.我尝试了 Doo Dah 的回答,但问题是它没有处理流程文档的页面填充。

Therefore I wrote my own solution (Doo Dah's answer helped me to complete it):因此,我编写了自己的解决方案(Doo Dah 的回答帮助我完成了它):

public FixedDocument Get_Fixed_From_FlowDoc(FlowDocument flowDoc, PrintDialog printDlg)
{
    var fixedDocument = new FixedDocument();
    try
    {
        pdlgPrint = printDlg ?? new PrintDialog();

        DocumentPaginator dpPages = (DocumentPaginator)((IDocumentPaginatorSource)flowDoc).DocumentPaginator;
        dpPages.ComputePageCount();
        PrintCapabilities capabilities = pdlgPrint.PrintQueue.GetPrintCapabilities(pdlgPrint.PrintTicket);

        for (int iPages= 0; iPages < dpPages.PageCount; iPages++)
        {
            var page = dpPages.GetPage(iPages);
            var pageContent = new PageContent();
            var fixedPage = new FixedPage();

            Canvas canvas = new Canvas();

            VisualBrush vb = new VisualBrush(page.Visual);
            vb.Stretch = Stretch.None;
            vb.AlignmentX = AlignmentX.Left;
            vb.AlignmentY = AlignmentY.Top;
            vb.ViewboxUnits = BrushMappingMode.Absolute;
            vb.TileMode = TileMode.None;
            vb.Viewbox = new Rect(0, 0, capabilities.PageImageableArea.ExtentWidth, capabilities.PageImageableArea.ExtentHeight);

            FixedPage.SetLeft(canvas, 0);
            FixedPage.SetTop(canvas, 0);
            canvas.Width = capabilities.PageImageableArea.ExtentWidth;
            canvas.Height = capabilities.PageImageableArea.ExtentHeight;
            canvas.Background = vb;

            fixedPage.Children.Add(canvas);

            fixedPage.Width = pdlgPrint.PrintableAreaWidth;
            fixedPage.Height = pdlgPrint.PrintableAreaHeight;
            pageContent.Child = fixedPage;
            fixedDocument.Pages.Add(pageContent);
        }
        dv1.ShowPageBorders = true;
    }
    catch (Exception)
    {
        throw;
    }
    return fixedDocument;
}

You had to build a FlowDocument of the content you will show before and pass it to the Method.您必须为之前将显示的内容构建一个 FlowDocument,并将其传递给 Method。
Added the PrintDialog variable to call the Method from my preview window and can pass the current printer settings.添加了 PrintDialog 变量以从我的预览窗口调用方法并可以传递当前的打印机设置。

If you call it from your main programm, you either can pass a new PrintDialog() or null , there is no difference, because it will create a new PrintDialog if you are passing null如果从主程序调用它,则可以传递new PrintDialog()null ,没有区别,因为如果传递null它将创建一个new PrintDialog

This worked fine for me with a Flowdocument with different types of text (header, text, font).对于具有不同类型文本(标题、文本、字体)的 Flowdocument,这对我来说效果很好。

It should work with pictures and text mixed, or only pictures, too - it's using the visuals and not something specific from a flowdocument, therefore it should work with pagebreaks, too.它应该使用混合的图片和文本,或者也只使用图片 - 它使用视觉效果而不是流程文档中的特定内容,因此它也应该与分页符一起使用。

I don't tryed Shahin Dohan'S answer, because it's the same problem as so often.我没有尝试过 Shahin Dohan 的回答,因为它经常出现同样的问题。
It's written at MVVM and very hard to understand when another person has written it.它是在 MVVM 上写的,很难理解是别人写的。
At my opinion it would be better to write a little example programm without mvvm and the people can adept it to mvvm or use only the code.在我看来,最好编写一个没有 mvvm 的小示例程序,人们可以熟练使用 mvvm 或仅使用代码。
I understand the opportunities of mvvm, but to show someone how to works something i see only disadvantages (if you will not show a specific mvvm mechanic)我了解 mvvm 的机会,但为了向某人展示如何工作,我只看到缺点(如果您不展示特定的 mvvm 技工)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM