WPF FixedPage具有相同的UserControl实例

时间:2017-01-24 15:42:29

标签: c# wpf printing fixeddocument fixedpage

首先,我不确定我是否正确地表达了这个标题。通过UserControls添加了ViewModel,我通过搜索VisualTree找到它们并将它们添加到ObservableCollection<Grid>。我想要做的是将我从UserControl检索到的VisualTree的每个实例打印到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");
        }
    }

这是我尝试打印三个标签时的样子(UserControls托管在标签中): As you can see here it prints three separate pages

我想在一个页面上全部三个,如果我打印10个标签,那么它应该填满第一页并继续下一页。

上次我问过类似的问题时,我被质疑是否编写了代码。此代码的各个部分来自FixedDocument上类似的StackOverflow个问题,但它已被编辑到实际适合我的程度。所以是的,我知道FixedPage中的foreach引用是什么导致创建三个单独的页面,我确实理解了代码。

要点:

我想知道的是如何从每个UserControls获取Tab到一个页面直到它完整,而没有得到“指定元素已经是另一个元素的逻辑子元素。”断开连接它首先。“错误。

1 个答案:

答案 0 :(得分:0)

我最终使用ItemsControlObservableCollection Controls ItemsControl作为列表,并使用此XpsDocumentWriter方法从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; } 打印。

SUM(
    NULL:[Accounting Date].[Calendar].CurrentMember,
    IIF(
        [Measures].[Amount] < 0,
        NULL,
        [Measures].[Amount] 
    )
)

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