简体   繁体   中英

Cannot print a document with landscape orientation under Windows 8 (WPF, .NET 4.0)

I have some simple WPF (.NET 4.0) application that works differently on Windows 7 and Windows 8.1. If I print a document and select Landscape orientation in Print Dialog or in code as shown below, Windows 8.1 truncates it (on the printer) as it would be portrait. (I have not seen this effect before under Windows 7).

    private void Print_Click(object sender, RoutedEventArgs e)
    {
        PrintDialog printDialog = new PrintDialog();

        printDialog.PrintQueue = System.Printing.LocalPrintServer.GetDefaultPrintQueue();
        printDialog.PrintTicket = printDialog.PrintQueue.DefaultPrintTicket;

        printDialog.PrintTicket.PageOrientation = System.Printing.PageOrientation.Landscape;

        if (printDialog.ShowDialog()??false)
        {
            //... ometed some code here

            GridPaginator paginator = new GridPaginator(...);

            printDialog.PrintDocument(paginator, "MyApp");
        }
    }

Any ideas, what was changed in Windows?

The trick to making this work is to set the PrintTicket.PageMediaSize property, using a newly-created PageMediaSize instance that specifies both the PageMediaSizeName and the width and height, with the dimensions translated to match the orientation.

PageMediaSizeName mediaSzNm = printDialog.PrintTicket.PageMediaSize.PageMediaSizeName.Value;
System.Windows.Size size = mediaSzNm.SizeInDips(printDialog.PrintTicket.PageOrientation.Value);
printDialog.PrintTicket.PageMediaSize = new PageMediaSize(mediaSzNm, size.Width, size.Height);

static public class PrintingHelper
{
  public const int Dpi = 96;

  // Get the page size, translated for page orientation
  public static Size SizeInDips(this PageMediaSizeName name, PageOrientation orientation)
  {
      if (orientation == PageOrientation.Landscape)
          return new Size(HeightInDips(name), WidthInDips(name));
      return new Size(WidthInDips(name), HeightInDips(name));
  }

  public static double WidthInDips(this PageMediaSizeName name)
  {
      return WidthInInches(name) * Dpi;
  }

  public static double HeightInDips(this PageMediaSizeName name)
  {
      return HeightInInches(name) * Dpi;
  }

    public static double WidthInInches(this PageMediaSizeName name)
    {
        if ((name == PageMediaSizeName.NorthAmericaLegal) || (name == PageMediaSizeName.NorthAmericaLetter))
            return 8.5;

        return 0;
    }

    public static double HeightInInches(this PageMediaSizeName name)
    {
        if (name == PageMediaSizeName.NorthAmericaLegal)
            return 14.0;
        else if (name == PageMediaSizeName.NorthAmericaLetter)
            return 11.0;

        return 0;
    }
}

Strange solution but works.

Get PrintDialog source code and save it in another class name. Delete internal references and ShowDialog method. (You can show dialog in your first object,then print with this)

My Edited Class :

using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Printing;
using System.Security;
using System.Security.Permissions;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Shapes;
using System.Windows.Xps;
using System.Xml;
using MS.Internal.Printing;
using System.Windows.Xps.Serialization;
using System.Windows.Documents;
using System.Windows.Documents.Serialization;  // WritingCompletedEventArgs 

using MS.Internal.PresentationFramework;

namespace System.Windows.Controls
{

    public class CustomPrintDialog
    {
        #region Constructors


        [SecurityCritical]
        public
        CustomPrintDialog(
            )
    {
        _dialogInvoked = false;

        _printQueue = null;
        _printTicket = null;

        _isPrintableAreaWidthUpdated = false;
        _isPrintableAreaHeightUpdated = false;

        _pageRangeSelection = PageRangeSelection.AllPages;
        _minPage = 1;
        _maxPage = 9999;
        _userPageRangeEnabled = false;
    }

        #endregion Constructors 

        #region Public properties 

        public PageRangeSelection PageRangeSelection
    {
        get
        {
            return _pageRangeSelection;
        }
        set
        {
            _pageRangeSelection = value;
        }
    }


        public PageRange PageRange
    {
        get
        {
            return _pageRange;
        }
        set
        {
            if ((value.PageTo <= 0) || (value.PageFrom <= 0))
            {
            }

            _pageRange = value;

            if (_pageRange.PageFrom > _pageRange.PageTo)
            {
                int temp = _pageRange.PageFrom;
                _pageRange.PageFrom = _pageRange.PageTo;
                _pageRange.PageTo = temp;
            }
        }
    }


        public bool UserPageRangeEnabled
    {
        get
        {
            return _userPageRangeEnabled;
        }
        set
        {
            _userPageRangeEnabled = value;
        }
    }


        public UInt32 MinPage
    {
        get
        {
            return _minPage;
        }
        set
        {
            if (_minPage <= 0)
            {
            }

            _minPage = value;
        }
    }

        public UInt32 MaxPage
    {
        get
        {
            return _maxPage;
        }
        set
        {
            if (_maxPage <= 0)
            {
            }

            _maxPage = value;
        }
    }

#pragma warning restore 3003


        public PrintQueue PrintQueue
    {
        [SecurityCritical]
        get
        {

            if (_printQueue == null)
            {
                _printQueue = AcquireDefaultPrintQueue();
            }

            return _printQueue;
        }
        [SecurityCritical]
        set
        {

            _printQueue = value;
        }
    }


        public PrintTicket PrintTicket
    {
        [SecurityCritical]
        get
        {

            if (_printTicket == null)
            {
                _printTicket = AcquireDefaultPrintTicket(this.PrintQueue);
            }

            return _printTicket;
        }
        [SecurityCritical]
        set
        {

            _printTicket = value;
        }
    }


        public
        double
        PrintableAreaWidth
    {
        get
        {
            if (((_isPrintableAreaWidthUpdated == false) && (_isPrintableAreaHeightUpdated == false)) ||
                ((_isPrintableAreaWidthUpdated == true) && (_isPrintableAreaHeightUpdated == false)))
            {
                _isPrintableAreaWidthUpdated = true;
                _isPrintableAreaHeightUpdated = false;

                UpdatePrintableAreaSize();
            }

            return _printableAreaWidth;
        }
    }


        public
        double
        PrintableAreaHeight
    {
        get
        {
            if (((_isPrintableAreaWidthUpdated == false) && (_isPrintableAreaHeightUpdated == false)) ||
                ((_isPrintableAreaWidthUpdated == false) && (_isPrintableAreaHeightUpdated == true)))
            {
                _isPrintableAreaWidthUpdated = false;
                _isPrintableAreaHeightUpdated = true;

                UpdatePrintableAreaSize();
            }
            return _printableAreaHeight;
        }
    }


        #endregion Public properties

        #region Public methods


        [SecurityCritical]
        public
        void
        PrintVisual(
            Visual visual,
            String description
            )
    {
        if (visual == null)
        {
            throw new ArgumentNullException("visual");
        }

        XpsDocumentWriter writer = CreateWriter(description);

        writer.Write(visual);

        _printableAreaWidth = 0;
        _printableAreaHeight = 0;
        _isPrintableAreaWidthUpdated = false;
        _isPrintableAreaHeightUpdated = false;
        _dialogInvoked = false;
    }



        [SecurityCritical]
        public
        void
        PrintDocument(
            DocumentPaginator documentPaginator,
            String description
            )
    {
        if (documentPaginator == null)
        {
            throw new ArgumentNullException("documentPaginator");
        }

        XpsDocumentWriter writer = CreateWriter(description);

        writer.Write(documentPaginator);

        _printableAreaWidth = 0;
        _printableAreaHeight = 0;
        _isPrintableAreaWidthUpdated = false;
        _isPrintableAreaHeightUpdated = false;
        _dialogInvoked = false;
    }

        #endregion Public methods


        [SecurityCritical]
        private
        PrintQueue
        AcquireDefaultPrintQueue()
    {
        PrintQueue printQueue = null;

         try
        {
            try
            {
                LocalPrintServer server = new LocalPrintServer();
                printQueue = server.DefaultPrintQueue;
            }
            catch (PrintSystemException)
            {
                //
                // It is entirely possible for there to be no "default" printer.  In this case, 
                // the printing system throws an exception.  We do not want this to propagate
                // up.  Instead, returning null is fine.
                //
                printQueue = null;
            }
        }
        finally
        {
         }

        return printQueue;
    }


        [SecurityCritical]
        private
        PrintTicket
        AcquireDefaultPrintTicket(
            PrintQueue printQueue
            )
    {
        PrintTicket printTicket = null;

         try
        {
            try
            {
                if (printQueue != null)
                {
                    printTicket = printQueue.UserPrintTicket;
                    if (printTicket == null)
                    {
                        printTicket = printQueue.DefaultPrintTicket;
                    }
                }
            }
            catch (PrintSystemException)
            {
                //
                // The printing subsystem can throw an exception in certain cases when 
                // the print ticket is unavailable.  If it does we will handle this
                // below.  There is no real need to bubble this up to the application.
                //
                printTicket = null;
            }
        }
        finally
        {
          }

        //
        // If the printing subsystem could not give us a print ticket either due to 
        // a failure or because a user/system default was not available, then just
        // create a blank/empty one. 
        // 
        if (printTicket == null)
        {
            printTicket = new PrintTicket();
        }

        return printTicket;
    }


        [SecurityCritical, SecurityTreatAsSafe]
        private
        void
        UpdatePrintableAreaSize(
            )
    {
        PrintQueue printQueue = null;
        PrintTicket printTicket = null;

        PickCorrectPrintingEnvironment(ref printQueue, ref printTicket);

        PrintCapabilities printCap = null;
        if (printQueue != null)
        {
            printCap = printQueue.GetPrintCapabilities(printTicket);
        }

        // PrintCapabilities OrientedPageMediaWidth/Height are Nullable
        if ((printCap != null) &&
            (printCap.OrientedPageMediaWidth != null) &&
            (printCap.OrientedPageMediaHeight != null))
        {
            _printableAreaWidth = (double)printCap.OrientedPageMediaWidth;
            _printableAreaHeight = (double)printCap.OrientedPageMediaHeight;
        }
        else
        {
            // Initialize page size to portrait Letter size. 
            // This is our fallback if PrintTicket doesn't specify the page size.
            _printableAreaWidth = 816;
            _printableAreaHeight = 1056;

            // PrintTicket's PageMediaSize could be null and PageMediaSize Width/Height are Nullable 

            if ((printTicket.PageMediaSize != null) &&
                (printTicket.PageMediaSize.Width != null) &&
                (printTicket.PageMediaSize.Height != null))
            {
                _printableAreaWidth = (double)printTicket.PageMediaSize.Width;
                _printableAreaHeight = (double)printTicket.PageMediaSize.Height;
            }

            // If we are using PrintTicket's PageMediaSize dimensions to populate the widht/height values,
            // we need to adjust them based on current orientation. PrintTicket's PageOrientation is Nullable.
            if (printTicket.PageOrientation != null)
            {
                PageOrientation orientation = (PageOrientation)printTicket.PageOrientation;

                // need to swap width/height in landscape orientation 
                if ((orientation == PageOrientation.Landscape) ||
                    (orientation == PageOrientation.ReverseLandscape))
                {
                    double t = _printableAreaWidth;
                    _printableAreaWidth = _printableAreaHeight;
                    _printableAreaHeight = t;
                }
            }
        }
    }


        [SecurityCritical, SecurityTreatAsSafe]
        private
        XpsDocumentWriter
        CreateWriter(
            String description
            )
    {
        PrintQueue printQueue = null;
        PrintTicket printTicket = null;
        XpsDocumentWriter writer = null;

        PickCorrectPrintingEnvironment(ref printQueue, ref printTicket);

         try
        {
            if (printQueue != null)
            {
                printQueue.CurrentJobSettings.Description = description;
            }

            writer = PrintQueue.CreateXpsDocumentWriter(printQueue);

            PrintDlgPrintTicketEventHandler eventHandler = new PrintDlgPrintTicketEventHandler(printTicket);

            writer.WritingPrintTicketRequired +=
            new WritingPrintTicketRequiredEventHandler(eventHandler.SetPrintTicket);
        }
        finally
        {
         }

        return writer;
    }


        [SecurityCritical]
        private
        void
        PickCorrectPrintingEnvironment(
            ref PrintQueue printQueue,
            ref PrintTicket printTicket
            )
    {
        if (_dialogInvoked == false)
        {
            //
            // If the dialog has not been invoked then the user needs printing permissions. 
            // If the demand succeeds then they can print.  If the demand fails, then we
            // tell them that the print dialog must be displayed first by throwing a dialog 
            // exception. 
            //
            try
            {

            }
            catch (SecurityException)
            {
             }
        }

        //
        // If the default print queue and print ticket have not already
        // been selected then update them now since we need them.
        // 
        // NOTE:  If this code gets called then we know the dialog has never
        //        been invoked but the above demand was satisfied.  In this 
        //        case we want to just pickup the user defaults. 
        //
        if (_printQueue == null)
        {
            _printQueue = AcquireDefaultPrintQueue();
        }
        if (_printTicket == null)
        {
            _printTicket = AcquireDefaultPrintTicket(_printQueue);
        }

        // 
        // We should have valid print queue and print ticket objects to
        // return now.  As a note, a null PrintQueue is valid for this
        // since the dialog will automatically pick up the user default
        // printer for us. 
        //
        printQueue = _printQueue;
        printTicket = _printTicket;
    }


        #region Private data

    /// <SecurityNote>
    /// The PrintTicket is critical and not obtainable from a partial 
    /// trust application unless they can satisfy a printing permission 
    /// demand.
    /// </SecurityNote> 
    [SecurityCritical]
    private
    PrintTicket _printTicket;

    /// <SecurityNote>
    /// The PrintQueue is critical and not obtainable from a partial 
    /// trust application unless they can satisfy a printing permission 
    /// demand.
    /// </SecurityNote> 
    [SecurityCritical]
    private
    PrintQueue _printQueue;

    /// <SecurityNote>
    /// This variable is used to determine whether a user actually invoked 
    /// and dismissed the dialog prior to printing.  In a partial trust app, 
    /// we can safely perform the necessary asserts to print as long as the
    /// user said printing was okay. 
    /// </SecurityNote>
    [SecurityCritical]
    private
    bool _dialogInvoked;

    private
    PageRangeSelection _pageRangeSelection;

    private
    PageRange _pageRange;

    private
    bool _userPageRangeEnabled;

    private
    UInt32 _minPage;

    private
    UInt32 _maxPage;

    private
    double _printableAreaWidth;

    private
    double _printableAreaHeight;

    private
    bool _isPrintableAreaWidthUpdated;

    private
    bool _isPrintableAreaHeightUpdated;

    #endregion Private data 

        #region Internal classes

        internal class PrintDlgPrintTicketEventHandler
    {
        #region Constructor

        /// <SecurityNote>
        ///     Critical    -   PrintTicket argument is critical because it is defined in the none APTCA assembly ReachFramework.dll 
        ///     TreatAsSafe -   PrintTicket type is safe 
        /// </SecurityNote>
        [SecurityCritical, SecurityTreatAsSafe]
        public
        PrintDlgPrintTicketEventHandler(
            PrintTicket printTicket
            )
        {
            _printTicket = printTicket;
        }

        #endregion Constructor 

        #region Public Methods

        /// <SecurityNote> 
        ///     Critical    -   Makes use of PrintTicket type which is critical because it is defined in the none APTCA assembly ReachFramework.dll
        ///                 -   Makes use of PrintTicketLevel type which is critical because it is defined in the none APTCA assembly ReachFramework.dll 
        ///     TreatAsSafe -   PrintTicket type is safe 
        /// </SecurityNote>
        [SecurityCritical, SecurityTreatAsSafe]
        public
        void
        SetPrintTicket(
            Object sender,
            WritingPrintTicketRequiredEventArgs args
            )
        {
            if (args.CurrentPrintTicketLevel == PrintTicketLevel.FixedDocumentSequencePrintTicket)
            {
                args.CurrentPrintTicket = _printTicket;
            }
        }

        #endregion Public Methods

        #region Private Data 

        private
        PrintTicket _printTicket;

        #endregion Private Data
    };

        #endregion Internal classes 
    }
}

Usage

        var pd = new CustomPrintDialog
        {
            PrintQueue = new PrintQueue(new PrintServer(), "THERMAL Receipt Printer"),
            PrintTicket = { PageOrientation = PageOrientation.Portrait }
        };


        pd.PrintVisual(this, "asdsa");

Can anyone explain how it works?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM