0

首先,我不确定我是否正确地表达了标题。有些是UserControls通过 a 添加的ViewModel,我通过搜索找到它们VisualTree并将它们添加到 a ObservableCollection<Grid>。我想做的是将UserControl我从 中检索到的每个实例打印VisualTree到 a中FixedDocument,但每个实例都UserControl在一个页面上,直到它填满该页面并移至下一页。

这是我当前的打印按钮单击事件的代码:

private async void btnPrint_Click(object sender, RoutedEventArgs e)
    {
        try
        {
            if (tabMain.Items.Count > 0)
            {
                tab = new TabLayout();

                tab.Payslip = new ObservableCollection<Grid>();


                foreach (var grid in FindVisualChildren<Grid>(this))
                {
                    if (grid.Name == "pdfFile")
                    {
                        tab.Payslip.Add(grid);
                    }
                }

                FrameworkElement toPrint = new FrameworkElement();
                PrintDialog printDialog = new 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();


                StackPanel panel = new StackPanel(); //was trying to stack them in a stackpanel first but it threw an exception about same instance of usercontrol blah blah...


                foreach (var doc in tab.Payslip.ToList())
                {

                    double yOffset = 0;

                    doc.Measure((new Size(double.PositiveInfinity, double.PositiveInfinity)));
                    doc.Arrange(new Rect(new Point(0, 0), doc.DesiredSize));

                    Size size = doc.DesiredSize;


                    while (yOffset < size.Height)
                    {
                        VisualBrush vb = new VisualBrush(doc);
                        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);

                        FixedPage page = new FixedPage();
                        PageContent pageContent = new PageContent();
                        ((IAddChild)pageContent).AddChild(page);
                        fixedDoc.Pages.Add(pageContent);
                        page.Width = fixedDoc.DocumentPaginator.PageSize.Width;
                        page.Height = fixedDoc.DocumentPaginator.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;
                    }
                }
                //printDialog.PrintDocument(fixedDoc.DocumentPaginator, "");
                ShowPrintPreview(fixedDoc);
            }
        }
        catch(Exception ex)
        {
            var exceptionDialog = new MessageDialog
            {
                Message = { Text = ex.ToString() }
            };

            await DialogHost.Show(exceptionDialog, "RootDialog");
        }
    }

这是我尝试打印三个选项卡时的样子(用户控件托管在选项卡中): 正如您在此处看到的,它打印三个单独的页面

我希望所有三个都在一个页面上,如果我打印 10 个标签,那么它应该填满第一页并继续到下一页。

上次我问了一个类似的问题,有人问我是否写了代码。这段代码的点点滴滴来自类似的FixedDocument问题,StackOverflow但它已经被编辑到它真正适合我的地步。所以是的,我知道FixedPage里面的引用foreach是导致创建三个单独页面的原因,我确实理解代码。

概括:

我想知道的是如何UserControls从 each中获取Tab, 到一个页面直到它满了,而不是得到“指定的元素已经是另一个元素的逻辑子元素。首先断开它。” 错误。

4

1 回答 1

0

我最终使用ItemsControl将我ObservableCollection的列表保存为列表并使用此方法Controls打印。ItemsControlXpsDocumentWriter

public void PrintItemsTo(ItemsControl ic, String jobName)
    {
        PrintDialog dlg = new PrintDialog();
        dlg.UserPageRangeEnabled = true;
        if (dlg.ShowDialog().GetValueOrDefault())
        {
            PageRange range = dlg.PageRange;
            //    range check - user selection starts from 1
            if (range.PageTo > ic.Items.Count)
                range.PageTo = ic.Items.Count;

            dlg.PrintQueue.CurrentJobSettings.Description = jobName;

            XpsDocumentWriter xdw = PrintQueue.CreateXpsDocumentWriter(dlg.PrintQueue);
            if (dlg.UserPageRangeEnabled == false || range.PageTo < range.PageFrom)
                WriteAllItems(ic, xdw);
            else
                WriteSelectedItems(ic, xdw, range);
        }
    }

    private void WriteAllItems(ItemsControl ic, XpsDocumentWriter xdw)
    {
        PageRange range = new PageRange(1, ic.Items.Count);
        WriteSelectedItems(ic, xdw, range);
    }

    private void WriteSelectedItems(ItemsControl ic, XpsDocumentWriter xdw, PageRange range)
    {
        IItemContainerGenerator generator = ic.ItemContainerGenerator;

        // write visuals using a batch operation
        VisualsToXpsDocument collator = (VisualsToXpsDocument)xdw.CreateVisualsCollator();

        collator.BeginBatchWrite();
        if (WritePageRange(collator, generator, range))
            collator.EndBatchWrite();
    }

    private bool WritePageRange(VisualsToXpsDocument collator, IItemContainerGenerator generator, PageRange range)
    {
        //    Get the generator position of the first data item
        //    PageRange reflects user's selection starts from 1
        GeneratorPosition startPos = generator.GeneratorPositionFromIndex(range.PageFrom - 1);
        //    If PageFrom > PageTo, print in reverse order
        //    UPDATE: never occurs; PrintDialog always 'normalises' the PageRange
        GeneratorDirection direction = (range.PageFrom <= range.PageTo) ? GeneratorDirection.Forward : GeneratorDirection.Backward;

        using (generator.StartAt(startPos, direction, true))
        {
            for (int numPages = Math.Abs(range.PageTo - range.PageFrom) + 1; numPages > 0; --numPages)
            {
                bool newlyRealized;

                // Get or create the child
                UIElement next = generator.GenerateNext(out newlyRealized) as UIElement;
                if (newlyRealized)
                {
                    generator.PrepareItemContainer(next);
                }

                //    The collator doesn't like ContentPresenters and produces blank pages
                //    for pages 2-n.  Finding the child of the ContentPresenter and writing
                //    that solves seems to solve the problem
                if (next is ContentPresenter)
                {
                    ContentPresenter presenter = (ContentPresenter)next;
                    presenter.UpdateLayout();
                    presenter.ApplyTemplate();    //    not sure if this is necessary
                    DependencyObject child = VisualTreeHelper.GetChild(presenter, 0);
                    if (child is UIElement)
                        next = (UIElement)child;
                }

                try
                {
                    collator.Write(next);
                }
                catch
                {
                    //    if user prints to Microsoft XPS Document Writer
                    //    and cancels the SaveAs dialog, we get an exception.
                    return false;
                }
            }
        }

        return true;
    }

PrintItemsTo() 显示一个 PrintDialog 以打印到任何打印机,而 WriteAllItems 显示一个对话框以另存为 PDF。

于 2017-02-10T21:26:11.853 回答