WPF固定文档分页

kokeuurv  于 2022-11-18  发布在  其他
关注(0)|答案(3)|浏览(140)

如何让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();
    }
u59ebvdq

u59ebvdq1#

我讨厌回答我自己的问题,但是,下面给了我一个合理的解决办法: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();
    }
}
6ju8rftf

6ju8rftf2#

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

Paginator.cs中的代码非常神奇,它检查了所有自定义的附加属性,并使用它们来确定在哪里设置页码、哪些元素只显示在第一页上,等等...

所有报表都定义为纯XAML用户控件,并在分页完成后转换为固定页。这样做的好处是,您可以用纯XAML定义文档/报表,添加一些附加属性,其余的工作由分页器代码完成。

**EDIT:**对于那些在理解代码方面有困难的人,您所需要做的就是创建一个工厂(Func),Paginator可以使用它来创建XAML UserControl的示例。

例如:

var reportFactory = () => new MyCoolUserControl();
var pages = await paginator.PaginateAsync(reportFactory, ...);

如果您想从这些页面获取FixedDocument,只需调用

var fixedDocument = paginator.GetFixedDocumentFromPages(pages, pageSize);

其余的代码只是一些MVVM的东西(我现在实际上会做得不同)和打印等等...

z4iuyo4d

z4iuyo4d3#

这个问题已经很久没有答案了。
我尝试了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变量以从预览窗口调用方法,并可以传递当前的打印机设置。
如果从主程序调用它,则可以传递new PrintDialog()null,没有区别,因为如果传递null,它将创建new PrintDialog
这对我来说很好地处理了一个具有不同类型文本(页眉、文本、字体)的Flowdocument。
它应该与图片和文本混合,或只有图片,太-它使用的是视觉效果,而不是从一个流程文档的具体东西,因此它应该与分页,太。
我没有尝试沙欣·多汉的答案,因为这是同样的问题,因为经常。
它是在MVVM写的,当另一个人写的时候很难理解。
在我看来,最好是写一个没有mvvm的小例子程序,人们可以把它改编成mvvm或者只使用代码。
我理解mvvm的机会,但要向某人展示如何工作的东西,我只看到缺点(如果你不会展示一个特定的mvvm机制)

相关问题