WPF打印适应页面

9

我搜索了一些关于如何打印WPF控件的选项,并找到了一些解决方案。我需要将我的打印控件适应打印页面并保持宽高比(我的控件是正方形;数独网格)。

我找到了一个解决方案,可以调整控件的大小和位置以适应页面。这个方法很好用,但它也会重新定位我的窗口上的控件。

以下是我用于打印和缩放的代码:

        //get selected printer capabilities
            System.Printing.PrintCapabilities capabilities = dialog.PrintQueue.GetPrintCapabilities(dialog.PrintTicket);
        //get scale of the print wrt to screen of WPF visual
        double scale = Math.Min(capabilities.PageImageableArea.ExtentWidth / mrizka.ActualWidth, capabilities.PageImageableArea.ExtentHeight / mrizka.ActualHeight);

        //Transform the Visual to scale
        mrizka.LayoutTransform = new ScaleTransform(scale, scale);

        //get the size of the printer page
        Size sz = new Size(capabilities.PageImageableArea.ExtentWidth, capabilities.PageImageableArea.ExtentHeight);

        //update the layout of the visual to the printer page size.
        mrizka.Measure(sz);
        mrizka.Arrange(new Rect(new Point(capabilities.PageImageableArea.OriginWidth, capabilities.PageImageableArea.OriginHeight), sz));

        dialog.PrintVisual(mrizka, mrizka.getID().ToString());

我尝试了两种方法来解决这个问题:
  1. 克隆我的控件,然后转换克隆的控件,不影响原始控件。但是由于某些原因,我最终遇到了异常:提供的DependencyObject不是此Freezable的上下文,但在某些情况下却很奇怪。

  2. 还原大小和位置的更改。我尝试调用InvalidateArrange()方法,它似乎有效,但仅在第一次调用打印方法时有效。在第二次调用期间,它没有起作用。

请问我该怎么做?有什么建议吗?谢谢。
2个回答

31

我知道这个问题很旧,但我自己也在寻找解决方案。 这是我目前正在使用的解决方案。 我将原始转换存储在框架元素中,然后在打印完成后重新应用它。

    private void Print(Visual v)
    {

        System.Windows.FrameworkElement e = v as System.Windows.FrameworkElement ;
        if (e == null)
            return;

        PrintDialog pd = new PrintDialog();
        if (pd.ShowDialog() == true)
        {
            //store original scale
            Transform originalScale = e.LayoutTransform;
            //get selected printer capabilities
            System.Printing.PrintCapabilities capabilities = pd.PrintQueue.GetPrintCapabilities(pd.PrintTicket);

            //get scale of the print wrt to screen of WPF visual
            double scale = Math.Min(capabilities.PageImageableArea.ExtentWidth / e.ActualWidth, capabilities.PageImageableArea.ExtentHeight /
                           e.ActualHeight);

            //Transform the Visual to scale
            e.LayoutTransform = new ScaleTransform(scale, scale);

            //get the size of the printer page
            System.Windows.Size sz = new System.Windows.Size(capabilities.PageImageableArea.ExtentWidth, capabilities.PageImageableArea.ExtentHeight);

            //update the layout of the visual to the printer page size.
            e.Measure(sz);
            e.Arrange(new System.Windows.Rect(new System.Windows.Point(capabilities.PageImageableArea.OriginWidth, capabilities.PageImageableArea.OriginHeight), sz));

            //now print the visual to printer to fit on the one page.
            pd.PrintVisual(v, "My Print");

            //apply the original transform.
            e.LayoutTransform = originalScale;
        }
    }

2
您需要添加对 System.Printing 和 ReachFramework 的引用。 - StillLearnin
它似乎还引用了 System.Windows.Media 和 System.Windows.Controls。 - Jeff
3
对我来说,这似乎无法正常工作,LayoutTransform 似乎无论我使用什么类型的 Transform ,都会被忽略。 - Lennart

1
    private void DrawGrap_Click(object sender, RoutedEventArgs e)
    {
        // Visual v = sender as Visual;
        Visual v = song2Grid as Visual;   // the object (it is a DataGrid) that you want to print out, not a window
        PrintDialog prtDlg = new PrintDialog();
        if (prtDlg.ShowDialog() == true)
        {
            // because 96 pixels in an inch for WPF window
            double marginLeft = 96.0 * 0.75; // left margin is 0.75 inches
            double marginTop = 96.0 * 0.75; // top margin is 0.75 inches
            double marginRight = 96.0 * 0.75; // right margin is 0.75 inches
            double marginBottom = 96.0 * 0.75; // bottom margin is 0.75 inches

            // the following steps do not works for a WPF window
            FrameworkElement win = v as FrameworkElement;
            Transform oldLayoutTransform = win.LayoutTransform;
            Size oldSize = new Size(win.ActualWidth, win.ActualHeight);

            System.Printing.PrintCapabilities pCapability = prtDlg.PrintQueue.GetPrintCapabilities(prtDlg.PrintTicket);

            // calculate print area that you want
            double printWidth = (pCapability.PageImageableArea.ExtentWidth - pCapability.PageImageableArea.OriginWidth)
                                - (marginLeft + marginRight);
            double printHeight = (pCapability.PageImageableArea.ExtentHeight - pCapability.PageImageableArea.OriginHeight)
                - (marginTop + marginBottom);

            // calculate the scale
            double scale = Math.Min(printWidth / oldSize.Width , printHeight / oldSize.Height);
            if (scale > 1.0)
            {
                // keep the original size and layout if printable area is greater than the object being printed
                scale = 1.0; 
            }

            // store the original layouttransform
            win.LayoutTransform = new ScaleTransform(scale, scale);

            // new size of the visual
            Size newSize = new Size(oldSize.Width*scale , oldSize.Height*scale);
            win.Measure(newSize);

            // centralize print area
            double xStartPrint = marginLeft + (printWidth - newSize.Width)/2.0;
            double yStartPrint = marginTop + (printHeight - newSize.Height)/2.0;
            win.Arrange(new Rect(new Point(xStartPrint,yStartPrint),newSize));

            // print out the visual
            prtDlg.PrintVisual(win as Visual, "PrintTest");

            // resotre the original layouttransform and size on screen
            win.LayoutTransform = oldLayoutTransform;
            win.Measure(oldSize);
            win.Arrange(new Rect(new Point(0,0),oldSize));
        }
    }

这是对user1018711提出的问题的答复。使用C#和WPF将打印内容适配到一页纸上。当您想要打印一个视觉对象时,它可能包含很多控件(例如按钮,数据网格,文本块,标签等)。这里我想要打印一个名为song2Drid的数据网格到打印机上,但其内容比打印纸张的大小要大(其宽度比纸张宽度更宽),因此被截断了。我无法看到所有内容,所以我必须缩放该视觉对象,但我希望保持与旧视觉对象相同的比例。

我还将纸张边距设置为每个纸张的0.75英寸,即左,上,右和下。我还将视觉对象(song2Grid)的内容居中在纸张上,因此我可以仅在纸张中心看到打印的内容。但是,如果该视觉对象是窗口,例如Application.Current.MainWindow或通过new Window()编程创建的任何窗口,则它将不会被缩放。这意味着该方法不适用于窗口对象。

此外,如果您想通过缩放以打印的方式恢复屏幕上的原始外观,则必须使用以下语句: win.LayoutTransform = oldLayoutTransform; win.Measure(oldSize); win.Arrange(new Rect(new Point(0,0),oldSize));

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接