【问题标题】:C# : Is there a way to save a Window as PDF?C#:有没有办法将 Window 保存为 PDF?
【发布时间】:2021-03-27 23:27:37
【问题描述】:

我正在使用 C# 生成一个有很多结果的窗口(滚动条):Window ResultsWindow = new Window();

在底部,有两个按钮,即取消和打印。第一个做它应该做的。尽管如此,打印按钮应该以某种方式将窗口转换为 PDF 文件,或者可能是用户可以在之后保存它的中间步骤。

    private void Print_click(object sender, RoutedEventArgs e)
    {   
        //add code to print the whole window??
        ResultsWindow.Close();            
    }

你们中有人知道这是如何工作的吗?

最好的问候

【问题讨论】:

  • 这个窗口到底是什么?也许您真的想保存正在显示的数据,而不是窗口本身? .NET 中有一些库可以生成 PDF 文件并允许您将数据插入其中。但是,如果您真的想要一个屏幕截图,那就另当别论了(尽管您提到了滚动条,所以屏幕截图可能不是很有用?)
  • 嗨,是的,其中的数据具有各自的颜色和格式。您指的是哪些库?
  • 有几个 .net 库作为 nuget 包提供,可用于生成 PDF。有些是免费的,有些不是。您需要在网上进行一些简单的搜索,看看是否能找到适合您情况的内容。
  • 注:如果您使用了颜色和格式,那是 UI 的一部分,而不是数据的一部分。因此,要制作不带屏幕截图的等效 PDF,您可能需要类似的逻辑来格式化 PDF 文档中与屏幕输出等效的数据。附言你没说这是 WinForms 还是 WPF 还是别的什么?
  • 好的,抱歉,我从哪里得到这个?我假设它是 WinForms,在标题中有: using System.Windows;使用 System.Windows.Controls;使用 System.Windows.Media;我也可以将输出保存为字符串或其他内容并将其保存为格式;或截屏输出窗口。是否可以截取一个窗口,即它的顶部,然后使用滚动条并截取底部?

标签: c# wpf windows pdf resultset


【解决方案1】:

假设您使用的是 WPF,以下是我完成类似操作的方法:

private void Button_Click(object sender, RoutedEventArgs e)
    {
        var wasMax = this.WindowState == WindowState.Maximized;
        UBlattWindow.WindowState = WindowState.Normal;
        var initHeight = UBlattWindow.ActualHeight;
        var initWidth = UBlattWindow.ActualWidth;
        UBlattWindow.Width = 955;
        UBlattWindow.Height = UBlattWindow.Height + (ScrollerContent.ActualHeight - Scroller.ActualHeight) + 20;

        Print(printGrid);
        UBlattWindow.Height = initHeight;
        UBlattWindow.Width = initWidth;
        if (wasMax)
        {
            UBlattWindow.WindowState = WindowState.Maximized;
        }
    }

    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)
        {
            PageMediaSize pageSize = null;

            pageSize = new PageMediaSize(PageMediaSizeName.ISOA4);

            pd.PrintTicket.PageMediaSize = pageSize;

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

请注意,我使用方法 Print 来缩放窗口,因此它将适合 ISOA4 格式。我还在打印之前将我的窗口设置为固定的宽度和高度,然后将其重置。

【讨论】:

    【解决方案2】:

    这不是特别漂亮(或经过测试),但使用来自 answer 的信息。

    这会为您的窗口创建一个 XPS 文件,并将其转换为 PDF

    using System.IO;
    using System.IO.Packaging;
    using System.Windows;
    using System.Windows.Xps;
    using System.Windows.Xps.Packaging;
    
    namespace WpfApp8
    {
        /// <summary>
        /// Interaction logic for MainWindow.xaml
        /// </summary>
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
            }
            private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
            {
                /*
                 *  Convert WPF -> XPS -> PDF
                 */
                MemoryStream lMemoryStream = new MemoryStream();
                Package package = Package.Open(lMemoryStream, FileMode.Create);
                XpsDocument doc = new XpsDocument(package);
                XpsDocumentWriter writer = XpsDocument.CreateXpsDocumentWriter(doc);
                
                // This is your window
                writer.Write(this);
    
                doc.Close();
                package.Close();
                
                // Convert 
                MemoryStream outStream = new MemoryStream();
                PdfSharp.Xps.XpsConverter.Convert(lMemoryStream, outStream, false);
    
                // Write pdf file
                FileStream fileStream = new FileStream("C:\\test.pdf", FileMode.Create);
                outStream.CopyTo(fileStream);
    
                // Clean up
                outStream.Flush();
                outStream.Close();
                fileStream.Flush();
                fileStream.Close();
            }
        }
    }
    

    它使用PdfSharp nuget 包和kenjiuno.PdfSharp.Xps 包将XPS 支持添加到PdfSharp

    【讨论】:

    • 嗨,我使用 System.Windows.Xps.Packaging 添加了;使用 System.Windows.Xps;以及 PdfSharp 和 kejiuno.PdfSharp.Xps 但运行脚本会生成错误消息:“命名空间名称 'Xps' 的类型在命名空间 'System.Windows' 中不存在(您是否缺少程序集引用?)”两次. 我没有得到我想念的东西
    • @shrox1740 我已经更新了答案以包含我的参考资料和完整的代码示例。您使用的是什么版本的 .NET/C#?
    • .NET 版本是 4.5,如果你是这个意思的话。看来我已经添加了您列出的所有参考资料。
    • 如果你没有说你已经添加了所有引用,我会假设ReachFramework dll 不存在。这似乎是网上最常见的原因。我假设您已经清理并重建了您的解决方案?
    • 我管理它并且它有效,但它只是窗口的屏幕截图。原则上很好,但它有一个滚动条,因此上半部分被剪掉了。到目前为止,我非常感谢,但是您知道解决最后一个问题的解决方案,以便打印整个窗口,可能打印到 PDF 上的 2 页?