| File: System\Windows\Controls\PrintDialog.cs | Web Access |
| Project: src\wpf\src\Microsoft.DotNet.Wpf\src\PresentationFramework\PresentationFramework.csproj (PresentationFramework) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. #if !DONOTREFPRINTINGASMMETA /* Abstract: This file contains the implementation of the PrintDialog class and its supporting enums. */ using System.Printing; using System.Windows.Media; using System.Windows.Xps; using MS.Internal.Printing; using System.Windows.Xps.Serialization; using System.Windows.Documents; using System.Windows.Documents.Serialization; // WritingCompletedEventArgs namespace System.Windows.Controls { /// <summary> /// This class is used to show a print which will configure a /// user PrintTicket and Printer based on user input. This /// PrintTicket and Printer is then used to perform a print job. /// </summary> public class PrintDialog { #region Constructors /// <summary> /// Instantiates an instance of the Print Dialog. /// </summary> public PrintDialog( ) { _printQueue = null; _printTicket = null; _isPrintableAreaWidthUpdated = false; _isPrintableAreaHeightUpdated = false; _pageRangeSelection = PageRangeSelection.AllPages; _minPage = 1; _maxPage = 9999; _userPageRangeEnabled = false; } #endregion Constructors #region Public properties /// <summary> /// Gets or Sets the PageRangeSelection option for the print dialog. /// </summary> public PageRangeSelection PageRangeSelection { get { return _pageRangeSelection; } set { _pageRangeSelection = value; } } /// <summary> /// Gets or sets a PageRange objects used when the PageRangeSelection /// option is set to UserPages. /// </summary> public PageRange PageRange { get { return _pageRange; } set { if ((value.PageTo <= 0) || (value.PageFrom <= 0)) { throw new System.ArgumentException(SR.PrintDialogInvalidPageRange, "PageRange"); } _pageRange = value; if (_pageRange.PageFrom > _pageRange.PageTo) { int temp = _pageRange.PageFrom; _pageRange.PageFrom = _pageRange.PageTo; _pageRange.PageTo = temp; } } } /// <summary> /// Gets or a sets a flag to enable/disable the user page range support on /// the print dialog. /// </summary> public bool UserPageRangeEnabled { get { return _userPageRangeEnabled; } set { _userPageRangeEnabled = value; } } /// <summary> /// Gets or a sets a flag to enable/disable the selected pages support on /// the print dialog. /// </summary> public bool SelectedPagesEnabled { get { return _selectedPagesEnabled; } set { _selectedPagesEnabled = value; } } /// <summary> /// Gets or a sets a flag to enable/disable the current page selection support on /// the print dialog. /// </summary> public bool CurrentPageEnabled { get { return _currentPageEnabled; } set { _currentPageEnabled = value; } } // the following two properties return non CLS-compliant type UInt32 (bug 1788246) #pragma warning disable 3003 /// <summary> /// Gets or sets the minimum page number allowed in the page ranges. /// </summary> public UInt32 MinPage { get { return _minPage; } set { if (_minPage <= 0) { throw new System.ArgumentException(SR.Format(SR.PrintDialogZeroNotAllowed, "MinPage")); } _minPage = value; } } /// <summary> /// Gets or sets the maximum page number allowed in the page ranges. /// </summary> public UInt32 MaxPage { get { return _maxPage; } set { if (_maxPage <= 0) { throw new System.ArgumentException(SR.Format(SR.PrintDialogZeroNotAllowed, "MaxPage")); } _maxPage = value; } } #pragma warning restore 3003 /// <summary> /// Gets or sets the printer selection. /// </summary> public PrintQueue PrintQueue { get { if (_printQueue == null) { _printQueue = AcquireDefaultPrintQueue(); } return _printQueue; } set { _printQueue = value; } } /// <summary> /// Get or sets the current PrintTicket object. /// </summary> public PrintTicket PrintTicket { get { if (_printTicket == null) { _printTicket = AcquireDefaultPrintTicket(this.PrintQueue); } return _printTicket; } set { _printTicket = value; } } /// <summary> /// Get the Width of the area on paper to which the application can print /// </summary> public double PrintableAreaWidth { get { if( ((!_isPrintableAreaWidthUpdated) && (!_isPrintableAreaHeightUpdated)) || ((_isPrintableAreaWidthUpdated) && (!_isPrintableAreaHeightUpdated))) { _isPrintableAreaWidthUpdated = true; _isPrintableAreaHeightUpdated = false; UpdatePrintableAreaSize(); } return _printableAreaWidth; } } /// <summary> /// Get the Height of the area on paper to which the application can print /// </summary> public double PrintableAreaHeight { get { if( ((!_isPrintableAreaWidthUpdated) && (!_isPrintableAreaHeightUpdated)) || ((!_isPrintableAreaWidthUpdated) && (_isPrintableAreaHeightUpdated))) { _isPrintableAreaWidthUpdated = false; _isPrintableAreaHeightUpdated = true; UpdatePrintableAreaSize(); } return _printableAreaHeight; } } #endregion Public properties #region Public methods /// <summary> /// Pops the dialog up to the user in a modal form. /// </summary> public Nullable<bool> ShowDialog() { Win32PrintDialog dlg = new Win32PrintDialog { // // Setup the old values if any exist. // PrintTicket = _printTicket, PrintQueue = _printQueue, MinPage = Math.Max(1, Math.Min(_minPage, _maxPage)) }; dlg.MaxPage = Math.Max(dlg.MinPage, Math.Max(_minPage, _maxPage)); dlg.PageRangeEnabled = _userPageRangeEnabled; dlg.SelectedPagesEnabled = _selectedPagesEnabled; dlg.CurrentPageEnabled = _currentPageEnabled; dlg.PageRange = new PageRange( Math.Max((int)dlg.MinPage, _pageRange.PageFrom), Math.Min((int)dlg.MaxPage, _pageRange.PageTo)); dlg.PageRangeSelection = _pageRangeSelection; // // Invoke the Win32 dialog // UInt32 dialogResult = dlg.ShowDialog(); if ((dialogResult == MS.Internal.Printing.NativeMethods.PD_RESULT_APPLY) || (dialogResult == MS.Internal.Printing.NativeMethods.PD_RESULT_PRINT)) { _printTicket = dlg.PrintTicket; _printQueue = dlg.PrintQueue; _pageRange = dlg.PageRange; _pageRangeSelection = dlg.PageRangeSelection; } return (dialogResult == MS.Internal.Printing.NativeMethods.PD_RESULT_PRINT); } /// <summary> /// Prints a Visual to the currently selected Print Queue. /// </summary> /// <param name="visual"> /// The visual to be printed. /// </param> /// <param name="description"> /// Description of the job to be printed. This shows in the Printer UI /// </param> public void PrintVisual( Visual visual, String description ) { ArgumentNullException.ThrowIfNull(visual); XpsDocumentWriter writer = CreateWriter(description); writer.Write(visual, _printTicket); _printableAreaWidth = 0; _printableAreaHeight = 0; _isPrintableAreaWidthUpdated = false; _isPrintableAreaHeightUpdated = false; } /// <summary> /// Prints an DocumentPaginator based document to the currently selected Print Queue. /// </summary> /// <param name="documentPaginator"> /// The DocumentPaginator to be printed. /// </param> /// <param name="description"> /// Description of the job to be printed. This shows in the Printer UI /// </param> public void PrintDocument( DocumentPaginator documentPaginator, String description ) { ArgumentNullException.ThrowIfNull(documentPaginator); XpsDocumentWriter writer = CreateWriter(description); writer.Write(documentPaginator, _printTicket); _printableAreaWidth = 0; _printableAreaHeight = 0; _isPrintableAreaWidthUpdated = false; _isPrintableAreaHeightUpdated = false; } #endregion Public methods #region Private methods private PrintQueue AcquireDefaultPrintQueue() { PrintQueue printQueue = null; 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; } return printQueue; } private PrintTicket AcquireDefaultPrintTicket( PrintQueue printQueue ) { PrintTicket printTicket = null; 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; } // // 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; } 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; } } } } private XpsDocumentWriter CreateWriter( String description ) { PrintQueue printQueue = null; PrintTicket printTicket = null; XpsDocumentWriter writer = null; PickCorrectPrintingEnvironment(ref printQueue, ref printTicket); printQueue?.CurrentJobSettings.Description = description; writer = PrintQueue.CreateXpsDocumentWriter(printQueue); PrintDlgPrintTicketEventHandler eventHandler = new PrintDlgPrintTicketEventHandler(printTicket); writer.WritingPrintTicketRequired += new WritingPrintTicketRequiredEventHandler(eventHandler.SetPrintTicket); return writer; } private void PickCorrectPrintingEnvironment( ref PrintQueue printQueue, ref PrintTicket printTicket ) { // // 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; } #endregion Private methods #region Private data private PrintTicket _printTicket; private PrintQueue _printQueue; private PageRangeSelection _pageRangeSelection; private PageRange _pageRange; private bool _userPageRangeEnabled; private bool _selectedPagesEnabled; private bool _currentPageEnabled; 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 public PrintDlgPrintTicketEventHandler( PrintTicket printTicket ) { _printTicket = printTicket; } #endregion Constructor #region Public Methods 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 } } #endif