10

如何让 FixedDocument 自动分页?我有以下代码可用于将美化面板放入 DocViewer。当面板超出单个页面时会出现问题。现在,我们只是剪辑。基本上,我想创建一种相当通用的方式来打印用户正在查看的内容。我的做法合理吗?

    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();
    }
4

3 回答 3

5

我讨厌回答我自己的问题,但是,以下给了我一个合理的解决方案: http ://social.msdn.microsoft.com/Forums/en-US/wpf/thread/bd89e0d2-73df-4b9b-9210-b8be83ff29d6/

斯科特

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();
    }
}
于 2011-02-24T20:10:34.040 回答
2

对于那些对不同且可能更“高级”的解决方案感兴趣的人,请继续查看在 GitHub 上的存储库,我在其中演示了如何创建 XAML 报告、对它们进行分页,然后从中生成可打印的 FixedDocument。

魔法发生在Paginator.cs中,代码遍历所有自定义附加属性并使用它们来确定在哪里设置页码,哪些元素只显示在第一页上,等等......

所有报告都定义为普通的 XAML 用户控件,并在分页完成后转换为固定页面。好处是您可以在纯 XAML 中定义文档/报告,添加一些附加属性,然后分页器代码负责其余的工作。

于 2020-02-11T07:31:11.703 回答
1

很久没有回答这个问题了。
我尝试了 Doo Dah 的回答,但问题是它没有处理流文档的页面填充。

因此,我编写了自己的解决方案(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;
}

您必须为之前将显示的内容构建一个 FlowDocument 并将其传递给方法。
添加了 PrintDialog 变量以从我的预览窗口调用方法,并且可以传递当前的打印机设置。

如果你从你的主程序中调用它,你可以传递 anew PrintDialog()null,没有区别,因为new PrintDialog如果你传递它会创建 anull

这对我来说很好用具有不同类型的文本(标题、文本、字体)的 Flowdocument .

它应该适用于混合的图片和文本,或者只适用于图片 - 它使用视觉效果而不是流文档中的特定内容,因此它也应该适用于分页符。

我没有尝试过 Shahin Dohan 的答案,因为它经常出现同样的问题。
它是在 MVVM 上编写的,当其他人编写它时很难理解。
在我看来,最好在没有 mvvm 的情况下编写一个小示例程序,人们可以熟练使用 mvvm 或仅使用代码。
我了解 mvvm 的机会,但是为了向某人展示如何工作,我只看到了缺点(如果您不展示特定的 mvvm 机制)

于 2020-08-15T10:40:52.663 回答