none
Issue with landscape printing using PrintVisual

    Question

  • I was playing around with Petzold's PrintWithMargins program from chapter 17 in his book "Applications = Code + Markup". The code is available at http://www.microsoft.com/mspress/companion/0-7356-1957-3/. The problem can be boiled down to having a window with a print button. The Click handler is as follows:

    void PrintOnClick(object sender, RoutedEventArgs args)
    {
      PrintDialog dialog = new PrintDialog();
    
      if (dialog.ShowDialog().GetValueOrDefault())
      {
        DrawingVisual visual = new DrawingVisual();
        DrawingContext context = visual.RenderOpen();
    
        Pen pen = new Pen(Brushes.Black, 1);
    
        Rect borderRect = new Rect(96, 96, 
          dialog.PrintableAreaWidth - 2 * 96, 
          dialog.PrintableAreaHeight - 2 * 96);
    
        context.DrawRectangle(null, pen, borderRect);
    
        context.Close();
        dialog.PrintVisual(visual, Title);
      }
    }
    
    

    So, it is just drawing a rectangle one inch from the edge of the printable area. I'm printing using Microsoft XPS Document Writer on Windows 7. The print dialog allows the user to choose orientation, Landscape or Portrait. The choice is reflected in different values for PrintableAreaWidth and PrintableAreaHeight. However, when using landscape orientation the resulting XPS document still displays (using XPS Viewer) as it had portrait orientation. The drawn rectangle is wider than tall, but is cut off on the right.

    I have the feeling that I need to do something additionally to indicate that the final document has height 8.5" and width 11".

    Thursday, October 21, 2010 8:57 PM

Answers

  • Hi carstenh_in,

    As to the Landscape printing issue, I must admit it is less desirable. Currently our developers are aware of this issue already. They will take this into serious account when designing the future releases of the products.

    The reason is that PrintDialog.PrintVisual does not accept user's print ticket settings. PrintDialog creates an instance of PrintDlgPrintTicketEventHandler with the user specified print ticket, created from the PrintDialog settings. However, it only checks for "FixedDocumentSequencePrintTicket". This does not fire with this argument when printing a Visual. So you couldn't achieve this by setting PrintTicket when you are using PrintVisual. 

    Hope it helps!

    Best regards,

    Yves


    Please remember to click “Mark as Answer” on the post that helps you, and to click “Unmark as Answer” if a marked post does not actually answer your question. This can be beneficial to other community members reading the thread.
    • Marked as answer by carstenh_in Friday, October 29, 2010 6:15 PM
    Friday, October 29, 2010 7:49 AM

All replies

  • Hi carstenh_in,

    The printer provides an unprinted margin around the edge of the paper, whereas the PrintDialog.PrintVisual method intends to print to the edge of the paper. The reason of this problem is the area that lies in the unprinted margin around the edge of the paper is clipped.

    Hope it helps.

     

    Best regards,

    Yves


    Please remember to click “Mark as Answer” on the post that helps you, and to click “Unmark as Answer” if a marked post does not actually answer your question. This can be beneficial to other community members reading the thread.
    Tuesday, October 26, 2010 11:41 AM
  • Hi Yves,

    My question is about Landscape printing. How do I print a visual so the final page is in Landscape mode?

    Carsten

    Tuesday, October 26, 2010 4:57 PM
  • Hi carstenh_in,

    As to the Landscape printing issue, I must admit it is less desirable. Currently our developers are aware of this issue already. They will take this into serious account when designing the future releases of the products.

    The reason is that PrintDialog.PrintVisual does not accept user's print ticket settings. PrintDialog creates an instance of PrintDlgPrintTicketEventHandler with the user specified print ticket, created from the PrintDialog settings. However, it only checks for "FixedDocumentSequencePrintTicket". This does not fire with this argument when printing a Visual. So you couldn't achieve this by setting PrintTicket when you are using PrintVisual. 

    Hope it helps!

    Best regards,

    Yves


    Please remember to click “Mark as Answer” on the post that helps you, and to click “Unmark as Answer” if a marked post does not actually answer your question. This can be beneficial to other community members reading the thread.
    • Marked as answer by carstenh_in Friday, October 29, 2010 6:15 PM
    Friday, October 29, 2010 7:49 AM
  • Hi Yves,

    Thanks for the reply.

    I ended up rewriting the code as follows:

    void PrintOnClick(object sender, RoutedEventArgs args)
    {
      PrintDialog dialog = new PrintDialog();
    
      if (dialog.ShowDialog().GetValueOrDefault())
      {
        DrawingVisual visual = new DrawingVisual();
        DrawingContext context = visual.RenderOpen();
    
        Pen pen = new Pen(Brushes.Black, 1);
    
        Rect borderRect = new Rect(96, 96, 
          dialog.PrintableAreaWidth - 2 * 96,
          dialog.PrintableAreaHeight - 2 * 96);
    
        context.DrawRectangle(null, pen, borderRect);
    
        context.Close();
    
        XpsDocumentWriter docWriter = 
          PrintQueue.CreateXpsDocumentWriter(dialog.PrintQueue);
        PrintTicket ticket = new PrintTicket();
        if (dialog.PrintTicket.PageOrientation == PageOrientation.Landscape)
        {
          ticket.PageMediaSize = 
            new PageMediaSize(dialog.PrintableAreaWidth, dialog.PrintableAreaHeight);
        }
        docWriter.Write(visual, ticket);
      }
    }
    
    

    Carsten

    Friday, October 29, 2010 6:15 PM
  • Thank you all for providing an answer to issue that was driving me nuts.  Here's some code which is finally helping me to get some decent screen printing.

    public static void PrintScreen(Visual visual /* to print*/, double width /* visual width*/, double height /* visual height*/, string message)
    {
        if (visual == null)
            return;
    PrintDialog printDialog = new PrintDialog();
    try
    {
        printDialog.PrintTicket.PageOrientation = System.Printing.PageOrientation.Landscape;
        printDialog.PrintTicket.PageBorderless = System.Printing.PageBorderless.Borderless;
    }
    catch { }  // not all printers support the above

    if (printDialog.ShowDialog() != true)
        return;

    StackPanel printCompositionPanel = new StackPanel();
    printCompositionPanel.ClipToBounds = true;
    printCompositionPanel.VerticalAlignment = VerticalAlignment.Center;
    Canvas canvas = new Canvas();
    canvas.Height = height;
    canvas.Width = width;
    canvas.ClipToBounds = true;
    canvas.Background = new VisualBrush(visual);

    System.Windows.Shapes.Rectangle rectangle = new System.Windows.Shapes.Rectangle
    {
        Fill = System.Windows.Media.Brushes.DarkGray,
        Height = 2d,
        Width = width,
        Margin = new Thickness(0d, 6d, 0d, 1d)
    };

    DateTime dtm = DateTime.Now;

    TextBlock dateText = new TextBlock
    {
        Margin = new Thickness(-20d, 4d, 20d, 0d),
        HorizontalAlignment = System.Windows.HorizontalAlignment.Right,
        Foreground = System.Windows.Media.Brushes.DarkGray,
        FontSize = 14d,
        Text = string.Format("{0} {1} {2}", message, dtm.ToShortDateString(),dtm.ToShortTimeString())
    };
    printCompositionPanel.Children.Add(canvas);
    printCompositionPanel.Children.Add(rectangle);
    printCompositionPanel.Children.Add(dateText);
    dateText.SetValue(Panel.ZIndexProperty, 100);

    Rect rect = new Rect(50, 50, 930, 730);
    try
    {
        //  Printer  drivers seems to leave margins around page.
        // Can't find way to access these margins. Therefore exclude 10% of area.
        double printableAreaHeight = printDialog.PrintableAreaHeight * 0.9d;
        double printableAreaWidth = printDialog.PrintableAreaWidth * 0.9d;
        double ratio = 1d;

        if (printDialog.PrintableAreaWidth > printDialog.PrintableAreaHeight) // landscape
            ratio = printableAreaHeight / (height + 50d);
        else
            ratio = printableAreaWidth / width;

        double adjustedheight = (height + 50d) * ratio;
        double adjustedwidth = width * ratio;

        System.Windows.Size printRectangleSize = new System.Windows.Size(adjustedwidth < printableAreaWidth ? adjustedwidth : printableAreaWidth,
                                            adjustedheight < printableAreaHeight ? adjustedheight : printableAreaHeight);

        // Size of rectangle in short depends on whether printing area is larger than screenshot or vice-a-versa.                            
        rect = new Rect(printRectangleSize);
        //rect.Location = new System.Windows.Point(10 / 2, 10 / 2);
        // Shrunk printable area due to margin issue. Therefore adjust  starting point plus add some padding
        rect.Location = new System.Windows.Point(
            (printDialog.PrintableAreaWidth - printableAreaWidth) / 2 + 5,
            (printDialog.PrintableAreaHeight - printableAreaHeight) / 2 + 5);
    }
    catch { }  // not all printers support PrintableAreaHeight, PrintableAreaHeight

    DrawingVisual printVisual = new DrawingVisual();
    DrawingContext context = printVisual.RenderOpen();
    VisualBrush vb = new VisualBrush(printCompositionPanel);

    context.DrawRectangle(vb, null, rect);
    context.Close(); // very important. if DrawingContext is not close there will be blank output.
    //printDialog.PrintVisual(dvisual, message != null ? message : string.Empty);

    // printdialog.PrintVisual seems to be working great with actual printer

    // but it creates issue when printing to XPS or PDF                        
    // XpsDocumentWriter.Write(...) is alternative method which solves the issue.

    XpsDocumentWriter docWriter = PrintQueue.CreateXpsDocumentWriter(printDialog.PrintQueue);
    PrintTicket ticket = printDialog.PrintTicket;
    // printDialog.PrintableAreaWidth is flipped when Orientation was set to landscape
    // but ticket.PageMediaSize.Width is not flipped i.e both properties are not integrated.
    ticket.PageMediaSize = new PageMediaSize(printDialog.PrintableAreaWidth, printDialog.PrintableAreaHeight);

    printCompositionPanel.RenderSize = rect.Size; // to avoid issues during printing to .xps file

    docWriter.Write(printVisual, ticket);

    }                              


    • Edited by purvin555 Wednesday, July 17, 2013 11:50 AM code update
    Monday, July 15, 2013 11:38 AM
  • Hi carstenh_in,

    As to the Landscape printing issue, I must admit it is less desirable. Currently our developers are aware of this issue already. They will take this into serious account when designing the future releases of the products.

    The reason is that PrintDialog.PrintVisual does not accept user's print ticket settings. PrintDialog creates an instance of PrintDlgPrintTicketEventHandler with the user specified print ticket, created from the PrintDialog settings. However, it only checks for "FixedDocumentSequencePrintTicket". This does not fire with this argument when printing a Visual. So you couldn't achieve this by setting PrintTicket when you are using PrintVisual. 

    Hope it helps!

    Best regards,

    Yves


    Please remember to click “Mark as Answer” on the post that helps you, and to click “Unmark as Answer” if a marked post does not actually answer your question. This can be beneficial to other community members reading the thread.

    Hi all,

    Any solution for this problem?

    The code is here proposed is not a case as we use multi page printing and XpsDocument and FixedDocument are not a case as well as they cause a lot of memory leaks and errors.

    Thank you.


    Assembler (.../z80/x86/x64...) the best language I've ever known

    Wednesday, July 23, 2014 6:33 PM