2

I am using C# to generate a Window (scrollbar) with a lot of results: Window ResultsWindow = new Window();

At the bottom, there are two buttons, i.e. Cancel and Print. The first one does what it should. Nevertheless, the Print button should somehow convert the Window into a PDF File, or maybe one step inbetween where the user can save it afterwards.

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

Does anyone of you have an idea how this could work?

Best regards

ADyson
  • 57,178
  • 14
  • 51
  • 63
shrox1740
  • 21
  • 2
  • what exactly is in this window? Perhaps you really want to save the data that is being displayed, rather than the window itself? There are libraries in .NET which can generate PDF files and allow you to insert data into them. However, if you literally want a screenshot that's a different matter (although you mentioned scrollbars so maybe a screenshot is not very useful?) – ADyson Dec 17 '20 at 09:31
  • Hi yes, the data in it with the respective colours and formatting. Which libraries do you mean? – shrox1740 Dec 17 '20 at 09:58
  • There are several .net libraries delivered as nuget packages which can be used to generate PDFs. Some are free, some are not. You need to do some simple searching online and see if you can find something which would fit your situation. – ADyson Dec 17 '20 at 10:00
  • N.B. If you have used colours and formatting, that is part of the UI and not part of the data. So to make an equivalent PDF without screenshotting, you'd likely need similar logic to format the data in the PDF document equivalent to the screen output. P.S. You didn't say if this is WinForms, or WPF, or something else? – ADyson Dec 17 '20 at 10:02
  • Ok sorry, where do I get this from? I assume it is WinForms, in the header there is: using System.Windows; using System.Windows.Controls; using System.Windows.Media; It would be okay for me as well to save the output as a string or something else and save this in the formatting; or to screenshot the outcoming window. Is it possible to screenshot a window, i.e. its top, then use the scrollbar and screenshot the bottom? – shrox1740 Dec 17 '20 at 10:14
  • "I assume it is WinForms"...it's your code, how do you not know what kind of project it is?? Look at the project properties, that should tell you. – ADyson Dec 17 '20 at 10:20
  • "Is it possible to screenshot a window, i.e. its top, then use the scrollbar and screenshot the bottom?"...perhaps but the results are likely to be c**p. – ADyson Dec 17 '20 at 10:20
  • It's WPF. Actually, I didn't code it initially and I am new to C#. Please excuse my points. Okay, maybe Screenshots are not the best option – shrox1740 Dec 17 '20 at 12:44
  • If you're new to C# then this awkward requirement is a terrible place to start learning. Get a core understanding of the problem and then come back to this. Otherwise you're unlikely to understand anything you research or any code we show you, in any case. – ADyson Dec 17 '20 at 13:32

2 Answers2

2

This isn't particularly pretty (or tested) but uses information from this answer.

This creates an XPS file of your window, and converts it to 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();
        }
    }
}

It uses the PdfSharp nuget package and the kenjiuno.PdfSharp.Xps package to add XPS support to PdfSharp

References

Morphed
  • 3,527
  • 2
  • 29
  • 55
  • Hi, I added using System.Windows.Xps.Packaging; using System.Windows.Xps; as well as PdfSharp and kejiuno.PdfSharp.Xps But running the script generates the error message: "The type of namespace name 'Xps' does not exist in the namespace 'System.Windows' (are you missing an assembly reference?)' twice. I don't get what I am missing – shrox1740 Dec 17 '20 at 13:40
  • 1
    @shrox1740 I've updated the answer to include my references and full code sample. What version of .NET/C# are you using? – Morphed Dec 17 '20 at 14:04
  • .NET version is 4.5, if you mean this. It seems that I have all the references that you list already added. – shrox1740 Dec 17 '20 at 15:31
  • If you hadn't said you have all the references added I would assume the `ReachFramework` dll wasn't there. That seems to be the most common reason online. I assume you've cleaned and rebuilt your solution? – Morphed Dec 17 '20 at 15:49
  • I managed it and it worked, but it is only a screenshot of the window. Which is in principle nice, but it has a scrollbar and therefore the upper half is cut. I am very thankful so far, but do you know a solution to fix this last issue so that the whole window is printed, maybe to 2 pages on a PDF? – shrox1740 Dec 18 '20 at 08:06
  • Have a search online. One method you could try uses the PrintDialog PrintVisual method, but that prints straight to the users printers, without the PDF conversion. I'm afraid this isn't my area of expertise. – Morphed Dec 18 '20 at 09:39
  • This solution works almost perfectly for me. The only nuget package that should be explicitly installed is nuget.org/packages/kenjiuno.PdfSharp.Xps. Important to note that the final PDF will have a white margin on the right and bottom of the page which is pretty unpleasant, but (@shrox1740) you can get rid of those by setting the Window.WindowStyle to "None" and the Window.ResizeMode to "NoResize". – Szabolcs Antal Mar 12 '23 at 17:04
0

Asuming you are using WPF, here is how I accomplished something similar:

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

Note that I use the method Print to scale the Window, so it will fit a ISOA4 format. I also set my window to a fixed width and height before the print and reset it afterwards.

Simon Tribus
  • 396
  • 2
  • 11