| File: System\Windows\Forms\Printing\PageSetupDialog.cs | Web Access |
| Project: src\winforms\src\System.Windows.Forms\System.Windows.Forms.csproj (System.Windows.Forms) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.ComponentModel; using System.Drawing.Printing; using System.Globalization; using Windows.Win32.UI.Controls.Dialogs; namespace System.Windows.Forms; /// <summary> /// Represents a dialog box that allows users to manipulate page settings, /// including margins and paper orientation. /// </summary> [DefaultProperty(nameof(Document))] [SRDescription(nameof(SR.DescriptionPageSetupDialog))] public sealed class PageSetupDialog : CommonDialog { // If PrintDocument is not null, pageSettings == printDocument.PageSettings private PrintDocument? _printDocument; private PageSettings? _pageSettings; private PrinterSettings? _printerSettings; private Margins? _minMargins; /// <summary> /// Initializes a new instance of the <see cref="PageSetupDialog"/> class. /// </summary> public PageSetupDialog() => Reset(); /// <summary> /// Gets or sets a value indicating whether the margins section of the dialog box is enabled. /// </summary> [SRCategory(nameof(SR.CatBehavior))] [DefaultValue(true)] [SRDescription(nameof(SR.PSDallowMarginsDescr))] public bool AllowMargins { get; set; } /// <summary> /// Gets or sets a value indicating whether the orientation section of the dialog box (landscape vs. portrait) /// is enabled. /// </summary> [SRCategory(nameof(SR.CatBehavior))] [DefaultValue(true)] [SRDescription(nameof(SR.PSDallowOrientationDescr))] public bool AllowOrientation { get; set; } /// <summary> /// Gets or sets a value indicating whether the paper section of the dialog box (paper size and paper source) /// is enabled. /// </summary> [SRCategory(nameof(SR.CatBehavior))] [DefaultValue(true)] [SRDescription(nameof(SR.PSDallowPaperDescr))] public bool AllowPaper { get; set; } /// <summary> /// Gets or sets a value indicating whether the Printer button is enabled. /// </summary> [SRCategory(nameof(SR.CatBehavior))] [DefaultValue(true)] [SRDescription(nameof(SR.PSDallowPrinterDescr))] public bool AllowPrinter { get; set; } /// <summary> /// Gets or sets a value indicating the <see cref="PrintDocument"/> to get page settings from. /// </summary> [SRCategory(nameof(SR.CatData))] [DefaultValue(null)] [SRDescription(nameof(SR.PDdocumentDescr))] public PrintDocument? Document { get => _printDocument; set { _printDocument = value; if (_printDocument is not null) { _pageSettings = _printDocument.DefaultPageSettings; _printerSettings = _printDocument.PrinterSettings; } } } /// <summary> /// This allows the user to override the current behavior where the Metric is converted to ThousandOfInch even /// for METRIC MEASUREMENTSYSTEM which returns a HUNDREDSOFMILLIMETER value. /// </summary> [DefaultValue(false)] [SRDescription(nameof(SR.PSDenableMetricDescr))] [Browsable(true)] [EditorBrowsable(EditorBrowsableState.Always)] public bool EnableMetric { get; set; } /// <summary> /// Gets or sets a value indicating the minimum margins the user is allowed to select, /// in hundredths of an inch. /// </summary> [SRCategory(nameof(SR.CatData))] [SRDescription(nameof(SR.PSDminMarginsDescr))] public Margins? MinMargins { get => _minMargins; set => _minMargins = value ?? new Margins(0, 0, 0, 0); } /// <summary> /// Gets or sets a value indicating the page settings modified by the dialog box. /// </summary> [SRCategory(nameof(SR.CatData))] [DefaultValue(null)] [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] [SRDescription(nameof(SR.PSDpageSettingsDescr))] public PageSettings? PageSettings { get => _pageSettings; set { _pageSettings = value; _printDocument = null; } } /// <summary> /// Gets or sets the printer settings the dialog box will modify if the user clicks the Printer button. /// </summary> [SRCategory(nameof(SR.CatData))] [DefaultValue(null)] [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] [SRDescription(nameof(SR.PSDprinterSettingsDescr))] public PrinterSettings? PrinterSettings { get => _printerSettings; set { _printerSettings = value; _printDocument = null; } } /// <summary> /// Gets or sets a value indicating whether the Help button is visible. /// </summary> [SRCategory(nameof(SR.CatBehavior))] [DefaultValue(false)] [SRDescription(nameof(SR.PSDshowHelpDescr))] public bool ShowHelp { get; set; } /// <summary> /// Gets or sets a value indicating whether the Network button is visible. /// </summary> [SRCategory(nameof(SR.CatBehavior))] [DefaultValue(true)] [SRDescription(nameof(SR.PSDshowNetworkDescr))] public bool ShowNetwork { get; set; } private PAGESETUPDLG_FLAGS GetFlags() { PAGESETUPDLG_FLAGS flags = PAGESETUPDLG_FLAGS.PSD_ENABLEPAGESETUPHOOK; if (!AllowMargins) { flags |= PAGESETUPDLG_FLAGS.PSD_DISABLEMARGINS; } if (!AllowOrientation) { flags |= PAGESETUPDLG_FLAGS.PSD_DISABLEORIENTATION; } if (!AllowPaper) { flags |= PAGESETUPDLG_FLAGS.PSD_DISABLEPAPER; } if (!AllowPrinter || _printerSettings is null) { flags |= PAGESETUPDLG_FLAGS.PSD_DISABLEPRINTER; } if (ShowHelp) { flags |= PAGESETUPDLG_FLAGS.PSD_SHOWHELP; } if (!ShowNetwork) { flags |= PAGESETUPDLG_FLAGS.PSD_NONETWORKBUTTON; } if (_minMargins is not null) { flags |= PAGESETUPDLG_FLAGS.PSD_MINMARGINS; } if (_pageSettings?.Margins is not null) { flags |= PAGESETUPDLG_FLAGS.PSD_MARGINS; } return flags; } /// <summary> /// Resets all options to their default values. /// </summary> public override void Reset() { AllowMargins = true; AllowOrientation = true; AllowPaper = true; AllowPrinter = true; MinMargins = null; // turns into Margin with all zeros _pageSettings = null; _printDocument = null; _printerSettings = null; ShowHelp = false; ShowNetwork = true; } // The next two methods are for designer support. private void ResetMinMargins() => MinMargins = null; /// <summary> /// Indicates whether the <see cref="MinMargins"/> property should be persisted. /// </summary> private bool ShouldSerializeMinMargins() => _minMargins is not null && (_minMargins.Left != 0 || _minMargins.Right != 0 || _minMargins.Top != 0 || _minMargins.Bottom != 0); private static void UpdateSettings( PAGESETUPDLGW data, PageSettings pageSettings, PrinterSettings? printerSettings) { pageSettings.SetHdevmode(data.hDevMode); if (printerSettings is not null) { printerSettings.SetHdevmode(data.hDevMode); printerSettings.SetHdevnames(data.hDevNames); } Margins newMargins = new() { Left = data.rtMargin.left, Top = data.rtMargin.top, Right = data.rtMargin.right, Bottom = data.rtMargin.bottom }; PrinterUnit fromUnit = ((data.Flags & PAGESETUPDLG_FLAGS.PSD_INHUNDREDTHSOFMILLIMETERS) != 0) ? PrinterUnit.HundredthsOfAMillimeter : PrinterUnit.ThousandthsOfAnInch; pageSettings.Margins = PrinterUnitConvert.Convert(newMargins, fromUnit, PrinterUnit.Display); } protected override unsafe bool RunDialog(IntPtr hwndOwner) { if (_pageSettings is null) { throw new ArgumentException(SR.PSDcantShowWithoutPage); } PAGESETUPDLGW dialogSettings = new() { lStructSize = (uint)sizeof(PAGESETUPDLGW), Flags = GetFlags(), hwndOwner = (HWND)hwndOwner, lpfnPageSetupHook = HookProcFunctionPointer }; PrinterUnit toUnit = PrinterUnit.ThousandthsOfAnInch; // EnableMetric allows the users to choose between the AutoConversion or not. if (EnableMetric) { // Take the Units of Measurement while determining the Printer Units. Span<char> buffer = stackalloc char[2]; int result; fixed (char* pBuffer = buffer) fixed (char* pLocaleName = PInvoke.LOCALE_NAME_SYSTEM_DEFAULT) { result = PInvoke.GetLocaleInfoEx( pLocaleName, PInvoke.LOCALE_IMEASURE, pBuffer, buffer.Length); } if (result > 0 && int.Parse(buffer, NumberStyles.Integer, CultureInfo.InvariantCulture) == 0) { toUnit = PrinterUnit.HundredthsOfAMillimeter; } } if (MinMargins is not null) { Margins margins = PrinterUnitConvert.Convert(MinMargins, PrinterUnit.Display, toUnit); dialogSettings.rtMinMargin.left = margins.Left; dialogSettings.rtMinMargin.top = margins.Top; dialogSettings.rtMinMargin.right = margins.Right; dialogSettings.rtMinMargin.bottom = margins.Bottom; } if (_pageSettings.Margins is not null) { Margins margins = PrinterUnitConvert.Convert(_pageSettings.Margins, PrinterUnit.Display, toUnit); dialogSettings.rtMargin.left = margins.Left; dialogSettings.rtMargin.top = margins.Top; dialogSettings.rtMargin.right = margins.Right; dialogSettings.rtMargin.bottom = margins.Bottom; } // Ensure that the margins are >= minMargins. // This is a requirement of the PAGESETUPDLG structure. dialogSettings.rtMargin.left = Math.Max(dialogSettings.rtMargin.left, dialogSettings.rtMinMargin.left); dialogSettings.rtMargin.top = Math.Max(dialogSettings.rtMargin.top, dialogSettings.rtMinMargin.top); dialogSettings.rtMargin.right = Math.Max(dialogSettings.rtMargin.right, dialogSettings.rtMinMargin.right); dialogSettings.rtMargin.bottom = Math.Max(dialogSettings.rtMargin.bottom, dialogSettings.rtMinMargin.bottom); PrinterSettings printer = _printerSettings ?? _pageSettings.PrinterSettings; dialogSettings.hDevMode = (HGLOBAL)printer.GetHdevmode(_pageSettings); dialogSettings.hDevNames = (HGLOBAL)printer.GetHdevnames(); try { if (!PInvoke.PageSetupDlg(&dialogSettings)) { return false; } // PrinterSettings, not printer UpdateSettings(dialogSettings, _pageSettings, _printerSettings); return true; } finally { PInvokeCore.GlobalFree(dialogSettings.hDevMode); PInvokeCore.GlobalFree(dialogSettings.hDevNames); } } }