简体   繁体   English

WPF打印/ xps问题

[英]WPF printing/xps issue

I have written the following chunk of code that prints my ListBox perfectly when being sent to a physical printer, however when trying to send it to the XPS printer driver or using the XpsDocumentWriter class (I assume they use the same code under the hood) I receive the following exception: 我编写了以下代码块,这些代码块在发送到物理打印机时可以完美打印我的ListBox,但是当尝试将其发送到XPS打印机驱动程序或使用XpsDocumentWriter类时(我假设他们在后台使用相同的代码)收到以下异常:

System.ArgumentException was unhandled by user code Message=Width and Height must be non-negative. 用户代码未处理System.ArgumentException消息=宽度和高度必须为非负数。 Source=ReachFramework StackTrace: at System.Windows.Xps.Serialization.VisualSerializer.WriteTileBrush(String element, TileBrush brush, Rect bounds) Source = ReachFramework StackTrace:位于System.Windows.Xps.Serialization.VisualSerializer.WriteTileBrush(字符串元素,TileBrush画笔,Rect范围)

The exception obviously points to an item not having a correct width/height however I have debugged the code when sending it to the different printers (physical and XPS driver) and I haven't been able to find any differences. 明显地,异常指向的项目没有正确的宽度/高度,但是当我将其发送到不同的打印机(物理打印机和XPS驱动程序)时,我已经调试了代码,但是我找不到任何区别。

Below is how I create the visual to send to the printer: 以下是我如何创建要发送到打印机的图像的方法:

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;
    }

Here is the GetPage override in my DocumentPaginator implementation: 这是我的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);
    }

Interestingly if I change the Fill of rectangle to a Brush instead of clone then I do not receive the exception and the outputted file is the correct size. 有趣的是,如果我将“矩形的填充”更改为“画笔”而不是克隆,则不会收到异常,并且输出的文件大小正确。

I have spent over a day trying to debug why this isn't working and I am hoping that someone out there has either seen a similar issue or is able to point out any mistakes I am making. 我花了整整一天的时间尝试调试为什么它不起作用,我希望那里的某个人已经看到了类似的问题,或者能够指出我正在犯的任何错误。

Thanks for any responses. 感谢您的任何答复。

Have you checked the value of ActualWidth and ActualHeight of myListBox when the VisualBrush is being created? 创建VisualBrush时是否检查了myListBox的ActualWidth和ActualHeight的值? I don't know from where myListBox comes, but if it is not rendered by the time you are generating your xps document you may run into problems. 我不知道myListBox来自哪里,但是如果在生成xps文档时未呈现它,则可能会遇到问题。 You can try to manually force the control to render and see if it makes any difference. 您可以尝试手动强制控件呈现,并查看它是否有所不同。

我无法解决问题,但是使用此链接可以对WPF视觉图像进行分页打印,从而找到了合适的解决方案,可以在WPF应用程序中进行复杂视觉图像的打印。

It's 2016 now and it's still not fixed. 现在是2016年,但仍未修复。 The problem is using TileBrush or any descendant type ( VisualBrush in your case). 问题是使用TileBrush或任何后代类型(在您的情况下为VisualBrush )。 If you use absolute mapping, it works, it's the relative mapping that causes the problem. 如果您使用绝对映射,那么它将起作用,这是导致问题的相对映射。 Calculate the final size yourself and set Viewport to this size, ViewportUnits to Absolute . 自己计算最终大小,然后将Viewport设置为此大小,将ViewportUnitsAbsolute Also make sure you don't use Stretch . 另外请确保您不使用Stretch

I had to give up finding a solution with VisualBrush. 我不得不放弃使用VisualBrush寻找解决方案。 If there is a GroupBox in the Visual for the brush I could never get it to produce a XPS file. 如果画笔中的Visual中有一个GroupBox,我将永远无法获取它来生成XPS文件。 It always fails with 它总是失败

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)

The workaround was to clone the content that should go in the VisualBrush ( Is there an easy/built-in way to get an exact copy (clone) of a XAML element? ) and use that directly in a Grid instead of an VisualBrush 解决方法是克隆应放在VisualBrush中的内容( 是否有一种简单/内置的方法来获取XAML元素的精确副本(克隆)? ),然后直接在Grid中而不是在VisualBrush中使用它

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM