【问题标题】:WPF Printing to fit pageWPF 打印以适合页面
【发布时间】:2011-12-17 10:23:29
【问题描述】:

我搜索了如何打印 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() 方法,该方法似乎有效,但仅在第一次调用 print 方法期间。在第二次通话期间,它没有工作。

请问我该怎么办,有什么想法

【问题讨论】:

    标签: .net wpf printing


    【解决方案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 在一个打印机页面上打印输出。当您想打印出一个视觉效果时,它可能是一个控件,其中可能包含许多控件(例如 Button、DataGrid、TextBlock、Label 等)。在这里,我想将一个名为 song2Drid 的 DataGrid 打印到打印机,但它的内容大于打印机的页面大小(它的宽度比纸张的宽度宽),所以它被截断了。我无法看到所有这些,所以我不得不缩放视觉效果,但我想保持与旧比例相同。

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

    另外,如果您想通过缩放打印来从更改后的屏幕上恢复原始外观,那么您必须具有以下语句 win.LayoutTransform = oldLayoutTransform; win.Measure(oldSize); win.Arrange(new Rect(new Point(0,0),oldSize));

    【讨论】:

      【解决方案2】:

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

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

      【讨论】:

      • 您需要添加对 System.Printing 和 ReachFramework 的引用。
      • 似乎也引用了 System.Windows.Media 和 System.Windows.Controls
      • 这对我来说不起作用,无论我向它抛出什么样的变换,LayoutTransform 似乎都被忽略了。