WPF打印/ xps问题

时间:2012-12-18 09:38:46

标签: c# wpf printing xps

我编写了以下代码块,可以在发送到物理打印机时完美地打印我的ListBox,但是在尝试将其发送到XPS打印机驱动程序或使用XpsDocumentWriter类时(我假设它们使用相同的代码)我收到以下例外:

System.ArgumentException未被用户代码处理   消息=宽度和高度必须是非负的。   来源= ReachFramework   堆栈跟踪:        在System.Windows.Xps.Serialization.VisualSerializer.WriteTileBrush(String element,TileBrush brush,Rect bounds)

该异常显然指向一个没有正确宽度/高度的项目但是我在将代码发送到不同的打印机(物理和XPS驱动程序)时调试了代码,但我找不到任何差异。

以下是我创建要发送到打印机的视觉效果的方法:

private ScrollViewer GeneratePrintableView()
    {
        ScrollViewer scrollView = new ScrollViewer();

        Grid grid = new Grid { Background = Brushes.White, Width = this.myListBox.ActualWidth, Height = this.myListBox.ActualHeight };

        grid.RowDefinitions.Add(new RowDefinition());
        grid.RowDefinitions[0].Height = new GridLength(0, GridUnitType.Auto);
        grid.RowDefinitions.Add(new RowDefinition());
        grid.RowDefinitions[1].Height = new GridLength(0, GridUnitType.Auto);

        // Add the title and icon to the top
        VisualBrush titleClone = new VisualBrush(this.TitleBar);
        var titleRectangle = new Rectangle { Fill = titleClone, Width = this.TitleBar.ActualWidth, Height = this.TitleBar.ActualHeight };
        grid.Children.Add(titleRectangle);
        Grid.SetRow(titleRectangle, 0);

        this.myListBox.Width = this.myListBox.ActualWidth;
        this.myListBox.Height = this.myListBox.ActualHeight;

        VisualBrush clone = new VisualBrush(this.myListBox) { Stretch = Stretch.None, AutoLayoutContent = true };
        var rectangle = new Rectangle { Fill = clone, Width = this.myListBox.ActualWidth, Height = this.myListBox.ActualHeight };
        Border border = new Border { Background = Brushes.White, Width = this.myListBox.ActualWidth, Height = this.myListBox.ActualHeight };
        border.Child = rectangle;
        grid.Children.Add(border);
        Grid.SetRow(border, 1);

        scrollView.Width = this.myListBox.ActualWidth;
        scrollView.Height = this.myListBox.ActualHeight;
        scrollView.Content = grid;
        scrollView.VerticalScrollBarVisibility = ScrollBarVisibility.Hidden;

        return scrollView;
    }

这是我的DocumentPaginator实现中的GetPage覆盖:

public override DocumentPage GetPage(int pageNumber)
    {
        Page page = new Page();
        double z = 0.0;

        this.grid = new Grid();
        this.grid.RowDefinitions.Add(new RowDefinition());
        this.grid.RowDefinitions[0].Height = new GridLength(0, GridUnitType.Auto);

        this.grid.Children.Add(this.printViewer);
        Grid.SetRow(this.printViewer, 0);

        //Adjusting the vertical scroll offset depending on the page number
        if (pageNumber + 1 == 1) //if First Page
        {
            this.printViewer.ScrollToVerticalOffset(0);
            this.printViewer.UpdateLayout();
        }
        else if (pageNumber + 1 == _verticalPageCount) //if Last Page
        {
            if (this.printViewer.ScrollableHeight == 0) //If printing only single page and the contents fits only on one page
            {
                this.printViewer.ScrollToVerticalOffset(0);
                this.printViewer.UpdateLayout();

            }
            else if (this.printViewer.ScrollableHeight <= this.printViewer.Height) //If scrollconentheight is less or equal than scrollheight
            {
                this.printViewer.Height = this.printViewer.ScrollableHeight;
                this.printViewer.ScrollToEnd();
                this.printViewer.UpdateLayout();
            }
            else //if the scrollcontentheight is greater than scrollheight then set the scrollviewer height to be the remainder between scrollcontentheight and scrollheight
            {
                this.printViewer.Height = (this.printViewer.ScrollableHeight % this.printViewer.Height) + 5;
                this.printViewer.ScrollToEnd();
                this.printViewer.UpdateLayout();
            }
        }
        else //Other Pages
        {
            z = z + this.printViewer.Height;
            this.printViewer.ScrollToVerticalOffset(z);
            this.printViewer.UpdateLayout();
        }

        page.Content = this.grid; //put the grid into the page
        page.Arrange(new Rect(this.originalMargin.Left, this.originalMargin.Top, this.ContentSize.Width, this.ContentSize.Height));
        page.UpdateLayout();

        return new DocumentPage(page);
    }

有趣的是,如果我将矩形的填充更改为Brush而不是clone,那么我不会收到异常并且输出的文件大小正确。

我花了一天多的时间试图调试为什么这不起作用,我希望那里有人看到过类似的问题,或者能够指出我正在犯的任何错误。

感谢您的回复。

4 个答案:

答案 0 :(得分:1)

在创建VisualBrush时,您是否检查过myListBox的ActualWidth和ActualHeight的值?我不知道myListBox来自哪里,但如果在生成xps文档时它没有呈现,则可能会遇到问题。您可以尝试manually force the control to render,看看它是否有所不同。

答案 1 :(得分:1)

我无法纠正这个问题,但使用此链接Paginated printing of WPF visuals我能找到一个合适的解决方案,允许在我的WPF应用程序中打印复杂的视觉效果。

答案 2 :(得分:1)

现在是2016年,它还没有修复。问题是在您的情况下使用TileBrush或任何后代类型(VisualBrush)。如果使用绝对映射,它可以工作,它是导致问题的相对映射。自己计算最终尺寸并将Viewport设置为此尺寸,ViewportUnits设为Absolute。另外,请确保您不使用Stretch

答案 3 :(得分:1)

我不得不放弃使用VisualBrush找到解决方案。如果Visual for the Brush中有一个GroupBox,我就永远无法生成一个XPS文件。它始终以

失败

System.ArgumentException was unhandled by user code Message=Width and Height must be non-negative. Source=ReachFramework StackTrace: at System.Windows.Xps.Serialization.VisualSerializer.WriteTileBrush(String element, TileBrush brush, Rect bounds)

解决方法是克隆应该放在VisualBrush(Is there an easy/built-in way to get an exact copy (clone) of a XAML element?)中的内容,并直接在Grid中使用它而不是VisualBrush