I have a dashboard filled with many user controls. These include text fields, check boxes, radio buttons, etc. This is a long form to fill in, so the controls are located in a scrollable panel. I need to save the entire panel in pdf format. I think that PDFsharp is a good library that allows you to save any text or image in pdf format, but I do not want to write code for each control inside the panel. I once wrote a class to create a PDF file from a Control object. He iterated over all the internal controls (and their internal controls until there was no internal control) of that control and wrote their Text property (yes / no for chekable controls) in pdf using their Location and Size properties. I could not find it now, but I remember that it had problems with some DevExpress controls that I used, so I did not write it again. (Edit: I had to, you can find it below.) I think I’m taking a picture and saving this image in pdf format, but I couldn’t figure out how to achieve it. This question seems to him, but there is no satisfactory answer to it.
So, a screenshot or not. I am open to any advice. There should be many cases where users must fill out long forms and be able to store them in pdf format. Again, any advice or workaround would be appreciated. (I am thinking of creating a form using html, displaying it in a WebBrowser control and using the html library in pdf, but I really prefer to use an existing form)
Thank you very much.
Edit: I had to write something to iterate the internal container controls (like a panel) and write each internal control in pdf using their Location, Size and Font properties, although I do not recommend using it (at least that's the way it is and there is) because of this:
- It sets the page size for a given control size and uses only one (usually huge) pdf page. You can add logic to divide it into pages if you need to. (I did not do this, but probably you will probably need your PDF file to print).
- The Cheeso method (using FlowDocument) is a much more legitimate way to do this. I prefer to use this, but in this case I had no choice.
In this code, I used PDFsharp. You can find it in this hompage or this is a CodePlex page .
PdfReport Class:
private PdfDocument Document; public Control Control { get; private set; } public PdfReport(Control control) { Control = control; } public PdfDocument CreatePdf(PdfDocument document = null) { Document = document != null ? document : new PdfDocument(); PdfPage page = Document.AddPage(); page.Height = Control.Height; page.Width = Control.Width; XGraphics gfx = XGraphics.FromPdfPage(page); foreach (PdfItem item in CreatePdf(new Point(0, 0), Control.Controls)) { XStringFormat format = item.IsContainer ? XStringFormats.TopLeft : item.TextAlign == ContentAlignment.BottomCenter ? XStringFormats.BottomCenter : item.TextAlign == ContentAlignment.TopLeft ? XStringFormats.TopLeft : item.TextAlign == ContentAlignment.TopCenter ? XStringFormats.TopCenter : XStringFormats.Center; gfx.DrawString(item.Text, item.Font, item.Brush, new XRect(item.Location, item.Size), format); } return Document; } private IEnumerable<PdfItem> CreatePdf(Point location, Control.ControlCollection controls) { List<PdfItem> items = new List<PdfItem>(); foreach (Control control in controls) { if (control.Controls.Count > 0) items.AddRange(CreatePdf(control.Location, control.Controls)); items.Add(new PdfItem(control, location)); } return items; } public void SaveAsPdf(string path, bool open = false) { CreatePdf().Save(path); if (open) Process.Start(path); }
PdfItem Class:
public string Text { get; set; } public Point Location { get; set; } public Size Size { get; set; } public Font Font { get; set; } public bool IsContainer { get; set; } public ContentAlignment TextAlign { get; set; } public Color ForeColor { get; set; } public XBrush Brush { get { return new SolidBrush(ForeColor); } } public PdfItem() { } public PdfItem(string text, Point location, Font font, Color foreColor, Size size, bool isContainer = false, ContentAlignment alignment = ContentAlignment.MiddleCenter) { Text = text; Location = location; Size = size; Font = new Font(font.FontFamily, font.Size, font.Style, GraphicsUnit.World); TextAlign = alignment; ForeColor = foreColor; IsContainer = isContainer; } public PdfItem(string text, Point location, Size size) : this(text, location, new Font("Calibri", 12), Color.Black, size) { } public PdfItem(Control control, Point parentLocation) : this(control.Text, control.Location, control.Font, control.ForeColor, control.Size, control.Controls.Count > 0) { Location = new Point(Location.X + parentLocation.X, Location.Y + parentLocation.Y); IEnumerable<PropertyInfo> properties = control.GetType().GetProperties(); if (properties.FirstOrDefault(p => p.Name == "TextAlign" && p.PropertyType == typeof(ContentAlignment)) != null) TextAlign = (control as dynamic).TextAlign; if (properties.FirstOrDefault(p => p.Name == "Checked" && p.PropertyType == typeof(bool)) != null) { string title = control.Text != null && control.Text.Length > 0 ? string.Format("{0}: ", control.Text) : string.Empty; Text = string.Format("{0}{1}", title, (control as dynamic).Checked ? "Yes" : "No"); } }