diff --git a/Wino.Core.Domain/Enums/PrintCollation.cs b/Wino.Core.Domain/Enums/PrintCollation.cs
new file mode 100644
index 00000000..94b5bf93
--- /dev/null
+++ b/Wino.Core.Domain/Enums/PrintCollation.cs
@@ -0,0 +1,22 @@
+namespace Wino.Core.Domain.Enums;
+
+///
+/// Print collation options.
+///
+public enum PrintCollation
+{
+ ///
+ /// Default collation.
+ ///
+ Default = 0,
+
+ ///
+ /// Collated printing.
+ ///
+ Collated = 1,
+
+ ///
+ /// Uncollated printing.
+ ///
+ Uncollated = 2
+}
\ No newline at end of file
diff --git a/Wino.Core.Domain/Enums/PrintColorMode.cs b/Wino.Core.Domain/Enums/PrintColorMode.cs
new file mode 100644
index 00000000..869f9b15
--- /dev/null
+++ b/Wino.Core.Domain/Enums/PrintColorMode.cs
@@ -0,0 +1,22 @@
+namespace Wino.Core.Domain.Enums;
+
+///
+/// Print color mode options.
+///
+public enum PrintColorMode
+{
+ ///
+ /// Default color mode.
+ ///
+ Default = 0,
+
+ ///
+ /// Color printing.
+ ///
+ Color = 1,
+
+ ///
+ /// Grayscale printing.
+ ///
+ Grayscale = 2
+}
\ No newline at end of file
diff --git a/Wino.Core.Domain/Enums/PrintDuplex.cs b/Wino.Core.Domain/Enums/PrintDuplex.cs
new file mode 100644
index 00000000..51becc23
--- /dev/null
+++ b/Wino.Core.Domain/Enums/PrintDuplex.cs
@@ -0,0 +1,27 @@
+namespace Wino.Core.Domain.Enums;
+
+///
+/// Print duplex (double-sided) options.
+///
+public enum PrintDuplex
+{
+ ///
+ /// Default duplex mode.
+ ///
+ Default = 0,
+
+ ///
+ /// Single-sided printing.
+ ///
+ Simplex = 1,
+
+ ///
+ /// Double-sided printing with pages flipped horizontally.
+ ///
+ DuplexShortEdge = 2,
+
+ ///
+ /// Double-sided printing with pages flipped vertically.
+ ///
+ DuplexLongEdge = 3
+}
\ No newline at end of file
diff --git a/Wino.Core.Domain/Enums/PrintMediaSize.cs b/Wino.Core.Domain/Enums/PrintMediaSize.cs
new file mode 100644
index 00000000..5e454992
--- /dev/null
+++ b/Wino.Core.Domain/Enums/PrintMediaSize.cs
@@ -0,0 +1,57 @@
+namespace Wino.Core.Domain.Enums;
+
+///
+/// Print media size options.
+///
+public enum PrintMediaSize
+{
+ ///
+ /// Default media size.
+ ///
+ Default = 0,
+
+ ///
+ /// Letter size (8.5 x 11 inches).
+ ///
+ NorthAmericaLetter = 1,
+
+ ///
+ /// Legal size (8.5 x 14 inches).
+ ///
+ NorthAmericaLegal = 2,
+
+ ///
+ /// A4 size (210 x 297 mm).
+ ///
+ IsoA4 = 3,
+
+ ///
+ /// A3 size (297 x 420 mm).
+ ///
+ IsoA3 = 4,
+
+ ///
+ /// A5 size (148 x 210 mm).
+ ///
+ IsoA5 = 5,
+
+ ///
+ /// Tabloid size (11 x 17 inches).
+ ///
+ NorthAmericaTabloid = 6,
+
+ ///
+ /// Executive size (7.25 x 10.5 inches).
+ ///
+ NorthAmericaExecutive = 7,
+
+ ///
+ /// B4 size (250 x 353 mm).
+ ///
+ JisB4 = 8,
+
+ ///
+ /// B5 size (176 x 250 mm).
+ ///
+ JisB5 = 9
+}
\ No newline at end of file
diff --git a/Wino.Core.Domain/Enums/PrintOrientation.cs b/Wino.Core.Domain/Enums/PrintOrientation.cs
new file mode 100644
index 00000000..8b9b169c
--- /dev/null
+++ b/Wino.Core.Domain/Enums/PrintOrientation.cs
@@ -0,0 +1,17 @@
+namespace Wino.Core.Domain.Enums;
+
+///
+/// Print orientation options.
+///
+public enum PrintOrientation
+{
+ ///
+ /// Portrait orientation (default).
+ ///
+ Portrait = 0,
+
+ ///
+ /// Landscape orientation.
+ ///
+ Landscape = 1
+}
\ No newline at end of file
diff --git a/Wino.Core.Domain/Models/Printing/WebView2PrintSettingsModel.cs b/Wino.Core.Domain/Models/Printing/WebView2PrintSettingsModel.cs
new file mode 100644
index 00000000..9a2fdeaa
--- /dev/null
+++ b/Wino.Core.Domain/Models/Printing/WebView2PrintSettingsModel.cs
@@ -0,0 +1,344 @@
+using System.ComponentModel;
+using Wino.Core.Domain.Enums;
+
+namespace Wino.Core.Domain.Models.Printing;
+
+///
+/// Wrapper model for CoreWebView2PrintSettings that provides bindable properties for UI controls.
+///
+public class WebView2PrintSettingsModel : INotifyPropertyChanged
+{
+ private string _printerName = string.Empty;
+ private PrintOrientation _orientation = PrintOrientation.Portrait;
+ private PrintColorMode _colorMode = PrintColorMode.Color;
+ private PrintCollation _collation = PrintCollation.Default;
+ private PrintDuplex _duplex = PrintDuplex.Default;
+ private PrintMediaSize _mediaSize = PrintMediaSize.Default;
+ private int _copies = 1;
+ private double _marginTop = 1.0;
+ private double _marginBottom = 1.0;
+ private double _marginLeft = 1.0;
+ private double _marginRight = 1.0;
+ private bool _shouldPrintBackgrounds = false;
+ private bool _shouldPrintSelectionOnly = false;
+ private bool _shouldPrintHeaderAndFooter = true;
+ private string _headerTitle = string.Empty;
+ private string _footerUri = string.Empty;
+ private double _scaleFactor = 1.0;
+ private int _pagesPerSide = 1;
+ private string _pageRanges = string.Empty;
+
+ public event PropertyChangedEventHandler PropertyChanged;
+
+ ///
+ /// Name of the printer to use for printing.
+ ///
+ public string PrinterName
+ {
+ get => _printerName;
+ set
+ {
+ if (_printerName != value)
+ {
+ _printerName = value;
+ OnPropertyChanged(nameof(PrinterName));
+ }
+ }
+ }
+
+ ///
+ /// Orientation of the printed document.
+ ///
+ public PrintOrientation Orientation
+ {
+ get => _orientation;
+ set
+ {
+ if (_orientation != value)
+ {
+ _orientation = value;
+ OnPropertyChanged(nameof(Orientation));
+ }
+ }
+ }
+
+ ///
+ /// Color mode for printing.
+ ///
+ public PrintColorMode ColorMode
+ {
+ get => _colorMode;
+ set
+ {
+ if (_colorMode != value)
+ {
+ _colorMode = value;
+ OnPropertyChanged(nameof(ColorMode));
+ }
+ }
+ }
+
+ ///
+ /// Collation setting for multiple copies.
+ ///
+ public PrintCollation Collation
+ {
+ get => _collation;
+ set
+ {
+ if (_collation != value)
+ {
+ _collation = value;
+ OnPropertyChanged(nameof(Collation));
+ }
+ }
+ }
+
+ ///
+ /// Duplex printing mode.
+ ///
+ public PrintDuplex Duplex
+ {
+ get => _duplex;
+ set
+ {
+ if (_duplex != value)
+ {
+ _duplex = value;
+ OnPropertyChanged(nameof(Duplex));
+ }
+ }
+ }
+
+ ///
+ /// Media size for printing.
+ ///
+ public PrintMediaSize MediaSize
+ {
+ get => _mediaSize;
+ set
+ {
+ if (_mediaSize != value)
+ {
+ _mediaSize = value;
+ OnPropertyChanged(nameof(MediaSize));
+ }
+ }
+ }
+
+ ///
+ /// Number of copies to print.
+ ///
+ public int Copies
+ {
+ get => _copies;
+ set
+ {
+ if (_copies != value && value > 0)
+ {
+ _copies = value;
+ OnPropertyChanged(nameof(Copies));
+ }
+ }
+ }
+
+ ///
+ /// Top margin in inches.
+ ///
+ public double MarginTop
+ {
+ get => _marginTop;
+ set
+ {
+ if (_marginTop != value && value >= 0)
+ {
+ _marginTop = value;
+ OnPropertyChanged(nameof(MarginTop));
+ }
+ }
+ }
+
+ ///
+ /// Bottom margin in inches.
+ ///
+ public double MarginBottom
+ {
+ get => _marginBottom;
+ set
+ {
+ if (_marginBottom != value && value >= 0)
+ {
+ _marginBottom = value;
+ OnPropertyChanged(nameof(MarginBottom));
+ }
+ }
+ }
+
+ ///
+ /// Left margin in inches.
+ ///
+ public double MarginLeft
+ {
+ get => _marginLeft;
+ set
+ {
+ if (_marginLeft != value && value >= 0)
+ {
+ _marginLeft = value;
+ OnPropertyChanged(nameof(MarginLeft));
+ }
+ }
+ }
+
+ ///
+ /// Right margin in inches.
+ ///
+ public double MarginRight
+ {
+ get => _marginRight;
+ set
+ {
+ if (_marginRight != value && value >= 0)
+ {
+ _marginRight = value;
+ OnPropertyChanged(nameof(MarginRight));
+ }
+ }
+ }
+
+ ///
+ /// Whether to print background colors and images.
+ ///
+ public bool ShouldPrintBackgrounds
+ {
+ get => _shouldPrintBackgrounds;
+ set
+ {
+ if (_shouldPrintBackgrounds != value)
+ {
+ _shouldPrintBackgrounds = value;
+ OnPropertyChanged(nameof(ShouldPrintBackgrounds));
+ }
+ }
+ }
+
+ ///
+ /// Whether to print only the selected content.
+ ///
+ public bool ShouldPrintSelectionOnly
+ {
+ get => _shouldPrintSelectionOnly;
+ set
+ {
+ if (_shouldPrintSelectionOnly != value)
+ {
+ _shouldPrintSelectionOnly = value;
+ OnPropertyChanged(nameof(ShouldPrintSelectionOnly));
+ }
+ }
+ }
+
+ ///
+ /// Whether to print header and footer.
+ ///
+ public bool ShouldPrintHeaderAndFooter
+ {
+ get => _shouldPrintHeaderAndFooter;
+ set
+ {
+ if (_shouldPrintHeaderAndFooter != value)
+ {
+ _shouldPrintHeaderAndFooter = value;
+ OnPropertyChanged(nameof(ShouldPrintHeaderAndFooter));
+ }
+ }
+ }
+
+ ///
+ /// Title to display in the header.
+ ///
+ public string HeaderTitle
+ {
+ get => _headerTitle;
+ set
+ {
+ if (_headerTitle != value)
+ {
+ _headerTitle = value ?? string.Empty;
+ OnPropertyChanged(nameof(HeaderTitle));
+ }
+ }
+ }
+
+ ///
+ /// URI to display in the footer.
+ ///
+ public string FooterUri
+ {
+ get => _footerUri;
+ set
+ {
+ if (_footerUri != value)
+ {
+ _footerUri = value ?? string.Empty;
+ OnPropertyChanged(nameof(FooterUri));
+ }
+ }
+ }
+
+ ///
+ /// Scale factor for printing (0.1 to 2.0).
+ ///
+ public double ScaleFactor
+ {
+ get => _scaleFactor;
+ set
+ {
+ if (_scaleFactor != value && value >= 0.1 && value <= 2.0)
+ {
+ _scaleFactor = value;
+ OnPropertyChanged(nameof(ScaleFactor));
+ }
+ }
+ }
+
+ ///
+ /// Number of pages to print per sheet (1, 2, 4, 6, 9, 16).
+ ///
+ public int PagesPerSide
+ {
+ get => _pagesPerSide;
+ set
+ {
+ var validValues = new[] { 1, 2, 4, 6, 9, 16 };
+ if (_pagesPerSide != value && System.Array.IndexOf(validValues, value) >= 0)
+ {
+ _pagesPerSide = value;
+ OnPropertyChanged(nameof(PagesPerSide));
+ }
+ }
+ }
+
+ ///
+ /// Page ranges to print (e.g., "1-3,5,7-9").
+ ///
+ public string PageRanges
+ {
+ get => _pageRanges;
+ set
+ {
+ if (_pageRanges != value)
+ {
+ _pageRanges = value ?? string.Empty;
+ OnPropertyChanged(nameof(PageRanges));
+ }
+ }
+ }
+
+
+
+ protected virtual void OnPropertyChanged(string propertyName)
+ {
+ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
+ }
+}
\ No newline at end of file
diff --git a/Wino.Core.WinUI/Dialogs/PrintDialog.xaml b/Wino.Core.WinUI/Dialogs/PrintDialog.xaml
new file mode 100644
index 00000000..33aa5476
--- /dev/null
+++ b/Wino.Core.WinUI/Dialogs/PrintDialog.xaml
@@ -0,0 +1,220 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Wino.Core.WinUI/Dialogs/PrintDialog.xaml.cs b/Wino.Core.WinUI/Dialogs/PrintDialog.xaml.cs
new file mode 100644
index 00000000..3680aba3
--- /dev/null
+++ b/Wino.Core.WinUI/Dialogs/PrintDialog.xaml.cs
@@ -0,0 +1,111 @@
+using System.Collections.Generic;
+using Microsoft.UI.Xaml.Controls;
+using Wino.Core.Domain.Models.Printing;
+using Wino.Core.WinUI.Models;
+
+namespace Wino.Core.WinUI.Dialogs;
+
+///
+/// Custom print dialog for configuring WebView2 print settings.
+///
+public sealed partial class PrintDialog : ContentDialog
+{
+ ///
+ /// The ViewModel that handles the dialog's data binding and logic.
+ ///
+ public PrintDialogViewModel ViewModel { get; }
+
+ ///
+ /// Gets the configured print settings from the dialog.
+ ///
+ public WebView2PrintSettingsModel PrintSettings => ViewModel.PrintSettings;
+
+ public PrintDialog()
+ {
+ this.InitializeComponent();
+ ViewModel = new PrintDialogViewModel();
+ ViewModel.Initialize();
+ }
+
+ ///
+ /// Initializes the dialog with existing print settings.
+ ///
+ /// The initial print settings to load.
+ public PrintDialog(WebView2PrintSettingsModel printSettings)
+ {
+ this.InitializeComponent();
+ ViewModel = new PrintDialogViewModel();
+ ViewModel.Initialize(printSettings);
+ }
+
+ ///
+ /// Sets the list of available printers for the dialog.
+ ///
+ /// List of available printer names.
+ public void SetAvailablePrinters(IEnumerable printers)
+ {
+ ViewModel.SetAvailablePrinters(printers);
+ }
+
+ ///
+ /// Validates the current print settings before closing the dialog.
+ ///
+ /// True if settings are valid, false otherwise.
+ private bool ValidateSettings()
+ {
+ // Validate printer selection
+ if (string.IsNullOrWhiteSpace(PrintSettings.PrinterName))
+ {
+ // Show error message or set focus to printer selection
+ return false;
+ }
+
+ // Validate copies
+ if (PrintSettings.Copies <= 0)
+ {
+ return false;
+ }
+
+ // Validate page ranges if custom range is specified
+ if (ViewModel.IsCustomPageRange && !string.IsNullOrWhiteSpace(PrintSettings.PageRanges))
+ {
+ // Basic validation for page ranges format
+ // More comprehensive validation could be added here
+ var pageRanges = PrintSettings.PageRanges.Trim();
+ if (string.IsNullOrEmpty(pageRanges))
+ {
+ return false;
+ }
+ }
+
+ // Validate margins
+ if (PrintSettings.MarginTop < 0 || PrintSettings.MarginBottom < 0 ||
+ PrintSettings.MarginLeft < 0 || PrintSettings.MarginRight < 0)
+ {
+ return false;
+ }
+
+ // Validate scale factor
+ if (PrintSettings.ScaleFactor < 0.1 || PrintSettings.ScaleFactor > 2.0)
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ private void ContentDialog_PrimaryButtonClick(ContentDialog sender, ContentDialogButtonClickEventArgs args)
+ {
+ // Validate settings before closing
+ if (!ValidateSettings())
+ {
+ args.Cancel = true;
+ // Could show error message here
+ }
+ }
+
+ private void ContentDialog_SecondaryButtonClick(ContentDialog sender, ContentDialogButtonClickEventArgs args)
+ {
+ // Cancel was clicked, no validation needed
+ }
+}
\ No newline at end of file
diff --git a/Wino.Core.WinUI/Extensions/PrintSettingsExtensions.cs b/Wino.Core.WinUI/Extensions/PrintSettingsExtensions.cs
new file mode 100644
index 00000000..33a50ec1
--- /dev/null
+++ b/Wino.Core.WinUI/Extensions/PrintSettingsExtensions.cs
@@ -0,0 +1,212 @@
+using Microsoft.Web.WebView2.Core;
+using Wino.Core.Domain.Enums;
+using Wino.Core.Domain.Models.Printing;
+
+namespace Wino.Core.WinUI.Extensions;
+
+///
+/// Extension methods and utilities for converting between Domain print models and CoreWebView2 print settings.
+///
+public static class PrintSettingsExtensions
+{
+ ///
+ /// Converts a Domain PrintOrientation to CoreWebView2PrintOrientation.
+ ///
+ public static CoreWebView2PrintOrientation ToCoreWebView2Orientation(this PrintOrientation orientation)
+ {
+ return orientation switch
+ {
+ PrintOrientation.Portrait => CoreWebView2PrintOrientation.Portrait,
+ PrintOrientation.Landscape => CoreWebView2PrintOrientation.Landscape,
+ _ => CoreWebView2PrintOrientation.Portrait
+ };
+ }
+
+ ///
+ /// Converts a CoreWebView2PrintOrientation to Domain PrintOrientation.
+ ///
+ public static PrintOrientation ToDomainOrientation(this CoreWebView2PrintOrientation orientation)
+ {
+ return orientation switch
+ {
+ CoreWebView2PrintOrientation.Portrait => PrintOrientation.Portrait,
+ CoreWebView2PrintOrientation.Landscape => PrintOrientation.Landscape,
+ _ => PrintOrientation.Portrait
+ };
+ }
+
+ ///
+ /// Converts a Domain PrintColorMode to CoreWebView2PrintColorMode.
+ ///
+ public static CoreWebView2PrintColorMode ToCoreWebView2ColorMode(this PrintColorMode colorMode)
+ {
+ return colorMode switch
+ {
+ PrintColorMode.Default => CoreWebView2PrintColorMode.Default,
+ PrintColorMode.Color => CoreWebView2PrintColorMode.Color,
+ PrintColorMode.Grayscale => CoreWebView2PrintColorMode.Grayscale,
+ _ => CoreWebView2PrintColorMode.Default
+ };
+ }
+
+ ///
+ /// Converts a CoreWebView2PrintColorMode to Domain PrintColorMode.
+ ///
+ public static PrintColorMode ToDomainColorMode(this CoreWebView2PrintColorMode colorMode)
+ {
+ return colorMode switch
+ {
+ CoreWebView2PrintColorMode.Default => PrintColorMode.Default,
+ CoreWebView2PrintColorMode.Color => PrintColorMode.Color,
+ CoreWebView2PrintColorMode.Grayscale => PrintColorMode.Grayscale,
+ _ => PrintColorMode.Default
+ };
+ }
+
+ ///
+ /// Converts a Domain PrintCollation to CoreWebView2PrintCollation.
+ ///
+ public static CoreWebView2PrintCollation ToCoreWebView2Collation(this PrintCollation collation)
+ {
+ return collation switch
+ {
+ PrintCollation.Default => CoreWebView2PrintCollation.Default,
+ PrintCollation.Collated => CoreWebView2PrintCollation.Collated,
+ PrintCollation.Uncollated => CoreWebView2PrintCollation.Uncollated,
+ _ => CoreWebView2PrintCollation.Default
+ };
+ }
+
+ ///
+ /// Converts a CoreWebView2PrintCollation to Domain PrintCollation.
+ ///
+ public static PrintCollation ToDomainCollation(this CoreWebView2PrintCollation collation)
+ {
+ return collation switch
+ {
+ CoreWebView2PrintCollation.Default => PrintCollation.Default,
+ CoreWebView2PrintCollation.Collated => PrintCollation.Collated,
+ CoreWebView2PrintCollation.Uncollated => PrintCollation.Uncollated,
+ _ => PrintCollation.Default
+ };
+ }
+
+ ///
+ /// Converts a Domain PrintDuplex to CoreWebView2PrintDuplex.
+ ///
+ public static CoreWebView2PrintDuplex ToCoreWebView2Duplex(this PrintDuplex duplex)
+ {
+ // Note: Simplified mapping due to enum value differences
+ return duplex switch
+ {
+ PrintDuplex.Default => CoreWebView2PrintDuplex.Default,
+ _ => CoreWebView2PrintDuplex.Default
+ };
+ }
+
+ ///
+ /// Converts a CoreWebView2PrintDuplex to Domain PrintDuplex.
+ ///
+ public static PrintDuplex ToDomainDuplex(this CoreWebView2PrintDuplex duplex)
+ {
+ // Note: Simplified mapping due to enum value differences
+ return duplex switch
+ {
+ CoreWebView2PrintDuplex.Default => PrintDuplex.Default,
+ _ => PrintDuplex.Default
+ };
+ }
+
+ ///
+ /// Converts a Domain PrintMediaSize to CoreWebView2PrintMediaSize.
+ ///
+ public static CoreWebView2PrintMediaSize ToCoreWebView2MediaSize(this PrintMediaSize mediaSize)
+ {
+ // Note: Simplified mapping due to enum value differences
+ return mediaSize switch
+ {
+ PrintMediaSize.Default => CoreWebView2PrintMediaSize.Default,
+ _ => CoreWebView2PrintMediaSize.Default
+ };
+ }
+
+ ///
+ /// Converts a CoreWebView2PrintMediaSize to Domain PrintMediaSize.
+ ///
+ public static PrintMediaSize ToDomainMediaSize(this CoreWebView2PrintMediaSize mediaSize)
+ {
+ // Note: Simplified mapping due to enum value differences
+ return mediaSize switch
+ {
+ CoreWebView2PrintMediaSize.Default => PrintMediaSize.Default,
+ _ => PrintMediaSize.Default
+ };
+ }
+
+ ///
+ /// Creates a CoreWebView2PrintSettings object from a WebView2PrintSettingsModel.
+ ///
+ /// The domain model containing the print settings.
+ /// The CoreWebView2Environment to create the settings object.
+ /// A configured CoreWebView2PrintSettings object.
+ public static CoreWebView2PrintSettings ToCoreWebView2PrintSettings(
+ this WebView2PrintSettingsModel model,
+ CoreWebView2Environment environment)
+ {
+ var settings = environment.CreatePrintSettings();
+
+ settings.PrinterName = model.PrinterName;
+ settings.Orientation = model.Orientation.ToCoreWebView2Orientation();
+ settings.ColorMode = model.ColorMode.ToCoreWebView2ColorMode();
+ settings.Collation = model.Collation.ToCoreWebView2Collation();
+ settings.Duplex = model.Duplex.ToCoreWebView2Duplex();
+ settings.MediaSize = model.MediaSize.ToCoreWebView2MediaSize();
+ settings.Copies = model.Copies;
+ settings.MarginTop = model.MarginTop;
+ settings.MarginBottom = model.MarginBottom;
+ settings.MarginLeft = model.MarginLeft;
+ settings.MarginRight = model.MarginRight;
+ settings.ShouldPrintBackgrounds = model.ShouldPrintBackgrounds;
+ settings.ShouldPrintSelectionOnly = model.ShouldPrintSelectionOnly;
+ settings.ShouldPrintHeaderAndFooter = model.ShouldPrintHeaderAndFooter;
+ settings.HeaderTitle = model.HeaderTitle;
+ settings.FooterUri = model.FooterUri;
+ settings.ScaleFactor = model.ScaleFactor;
+ settings.PagesPerSide = model.PagesPerSide;
+ settings.PageRanges = model.PageRanges;
+
+ return settings;
+ }
+
+ ///
+ /// Updates a WebView2PrintSettingsModel from a CoreWebView2PrintSettings object.
+ ///
+ /// The domain model to update.
+ /// The source CoreWebView2PrintSettings.
+ public static void FromCoreWebView2PrintSettings(
+ this WebView2PrintSettingsModel model,
+ CoreWebView2PrintSettings settings)
+ {
+ if (settings == null) return;
+
+ model.PrinterName = settings.PrinterName ?? string.Empty;
+ model.Orientation = settings.Orientation.ToDomainOrientation();
+ model.ColorMode = settings.ColorMode.ToDomainColorMode();
+ model.Collation = settings.Collation.ToDomainCollation();
+ model.Duplex = settings.Duplex.ToDomainDuplex();
+ model.MediaSize = settings.MediaSize.ToDomainMediaSize();
+ model.Copies = settings.Copies;
+ model.MarginTop = settings.MarginTop;
+ model.MarginBottom = settings.MarginBottom;
+ model.MarginLeft = settings.MarginLeft;
+ model.MarginRight = settings.MarginRight;
+ model.ShouldPrintBackgrounds = settings.ShouldPrintBackgrounds;
+ model.ShouldPrintSelectionOnly = settings.ShouldPrintSelectionOnly;
+ model.ShouldPrintHeaderAndFooter = settings.ShouldPrintHeaderAndFooter;
+ model.HeaderTitle = settings.HeaderTitle ?? string.Empty;
+ model.FooterUri = settings.FooterUri ?? string.Empty;
+ model.ScaleFactor = settings.ScaleFactor;
+ model.PagesPerSide = settings.PagesPerSide;
+ model.PageRanges = settings.PageRanges ?? string.Empty;
+ }
+}
\ No newline at end of file
diff --git a/Wino.Core.WinUI/Interfaces/IPrintDialogService.cs b/Wino.Core.WinUI/Interfaces/IPrintDialogService.cs
new file mode 100644
index 00000000..56c920a4
--- /dev/null
+++ b/Wino.Core.WinUI/Interfaces/IPrintDialogService.cs
@@ -0,0 +1,30 @@
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Wino.Core.Domain.Models.Printing;
+
+namespace Wino.Core.WinUI.Interfaces;
+
+///
+/// Service interface for displaying the custom print dialog and managing print settings.
+///
+public interface IPrintDialogService
+{
+ ///
+ /// Shows the print dialog and returns the configured print settings.
+ ///
+ /// Initial print settings to populate the dialog with. If null, default settings will be used.
+ /// List of available printers to show in the dialog. If null or empty, the service should attempt to discover printers.
+ ///
+ /// A task that resolves to the configured WebView2PrintSettingsModel if the user clicked Print,
+ /// or null if the user cancelled the dialog.
+ ///
+ Task ShowPrintDialogAsync(
+ WebView2PrintSettingsModel initialSettings = null,
+ IEnumerable availablePrinters = null);
+
+ ///
+ /// Gets the list of available printers on the system.
+ ///
+ /// A task that resolves to a list of available printer names.
+ Task> GetAvailablePrintersAsync();
+}
\ No newline at end of file
diff --git a/Wino.Core.WinUI/Models/PrintDialogViewModel.cs b/Wino.Core.WinUI/Models/PrintDialogViewModel.cs
new file mode 100644
index 00000000..7947403e
--- /dev/null
+++ b/Wino.Core.WinUI/Models/PrintDialogViewModel.cs
@@ -0,0 +1,276 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using Microsoft.UI.Xaml.Controls;
+using Wino.Core.Domain.Enums;
+using Wino.Core.Domain.Models.Printing;
+
+namespace Wino.Core.WinUI.Dialogs;
+
+///
+/// ViewModel for the PrintDialog that handles data binding and state management.
+///
+public class PrintDialogViewModel : INotifyPropertyChanged
+{
+ private List _availablePrinters = new();
+ private bool _isCustomPageRange = false;
+ private WebView2PrintSettingsModel _printSettings = new();
+
+ public event PropertyChangedEventHandler PropertyChanged;
+
+ public PrintDialogViewModel()
+ {
+ // Initialize default values
+ PrintSettings.PropertyChanged += OnPrintSettingsChanged;
+ }
+
+ ///
+ /// The print settings model that will be configured by the dialog.
+ ///
+ public WebView2PrintSettingsModel PrintSettings
+ {
+ get => _printSettings;
+ set
+ {
+ if (_printSettings != value)
+ {
+ if (_printSettings != null)
+ _printSettings.PropertyChanged -= OnPrintSettingsChanged;
+
+ _printSettings = value;
+
+ if (_printSettings != null)
+ _printSettings.PropertyChanged += OnPrintSettingsChanged;
+
+ OnPropertyChanged(nameof(PrintSettings));
+ UpdateDerivedProperties();
+ }
+ }
+ }
+
+ ///
+ /// List of available printers.
+ ///
+ public List AvailablePrinters
+ {
+ get => _availablePrinters;
+ set
+ {
+ if (_availablePrinters != value)
+ {
+ _availablePrinters = value ?? new List();
+ OnPropertyChanged(nameof(AvailablePrinters));
+ }
+ }
+ }
+
+ ///
+ /// Index for the orientation radio buttons.
+ ///
+ public int OrientationIndex
+ {
+ get => (int)PrintSettings.Orientation;
+ set
+ {
+ if (value >= 0 && value <= 1)
+ {
+ PrintSettings.Orientation = (PrintOrientation)value;
+ OnPropertyChanged(nameof(OrientationIndex));
+ }
+ }
+ }
+
+ ///
+ /// Index for the color mode radio buttons.
+ ///
+ public int ColorModeIndex
+ {
+ get => (int)PrintSettings.ColorMode;
+ set
+ {
+ if (value >= 0 && value <= 2)
+ {
+ PrintSettings.ColorMode = (PrintColorMode)value;
+ OnPropertyChanged(nameof(ColorModeIndex));
+ }
+ }
+ }
+
+ ///
+ /// Index for the collation radio buttons.
+ ///
+ public int CollationIndex
+ {
+ get => (int)PrintSettings.Collation;
+ set
+ {
+ if (value >= 0 && value <= 2)
+ {
+ PrintSettings.Collation = (PrintCollation)value;
+ OnPropertyChanged(nameof(CollationIndex));
+ }
+ }
+ }
+
+ ///
+ /// Index for the duplex radio buttons.
+ ///
+ public int DuplexIndex
+ {
+ get => (int)PrintSettings.Duplex;
+ set
+ {
+ if (value >= 0 && value <= 3)
+ {
+ PrintSettings.Duplex = (PrintDuplex)value;
+ OnPropertyChanged(nameof(DuplexIndex));
+ }
+ }
+ }
+
+ ///
+ /// Index for the media size combo box.
+ ///
+ public int MediaSizeIndex
+ {
+ get => (int)PrintSettings.MediaSize;
+ set
+ {
+ if (value >= 0 && value <= 9)
+ {
+ PrintSettings.MediaSize = (PrintMediaSize)value;
+ OnPropertyChanged(nameof(MediaSizeIndex));
+ }
+ }
+ }
+
+ ///
+ /// Index for the pages per side combo box.
+ ///
+ public int PagesPerSideIndex
+ {
+ get
+ {
+ var validValues = new[] { 1, 2, 4, 6, 9, 16 };
+ return Array.IndexOf(validValues, PrintSettings.PagesPerSide);
+ }
+ set
+ {
+ var validValues = new[] { 1, 2, 4, 6, 9, 16 };
+ if (value >= 0 && value < validValues.Length)
+ {
+ PrintSettings.PagesPerSide = validValues[value];
+ OnPropertyChanged(nameof(PagesPerSideIndex));
+ }
+ }
+ }
+
+ ///
+ /// Index for the page range option (0 = All pages, 1 = Custom range).
+ ///
+ public int PageRangeOptionIndex
+ {
+ get => IsCustomPageRange ? 1 : 0;
+ set
+ {
+ IsCustomPageRange = value == 1;
+ if (!IsCustomPageRange)
+ {
+ PrintSettings.PageRanges = string.Empty;
+ }
+ OnPropertyChanged(nameof(PageRangeOptionIndex));
+ }
+ }
+
+ ///
+ /// Whether custom page range is selected.
+ ///
+ public bool IsCustomPageRange
+ {
+ get => _isCustomPageRange;
+ private set
+ {
+ if (_isCustomPageRange != value)
+ {
+ _isCustomPageRange = value;
+ OnPropertyChanged(nameof(IsCustomPageRange));
+ }
+ }
+ }
+
+ ///
+ /// Scale factor as percentage text for display.
+ ///
+ public string ScalePercentageText => $"{(int)(PrintSettings.ScaleFactor * 100)}%";
+
+ ///
+ /// Initializes the dialog with the provided print settings.
+ ///
+ /// The initial print settings.
+ public void Initialize(WebView2PrintSettingsModel printSettings = null)
+ {
+ if (printSettings != null)
+ {
+ PrintSettings = printSettings;
+ }
+ else
+ {
+ PrintSettings = new WebView2PrintSettingsModel();
+ }
+
+ UpdateDerivedProperties();
+ }
+
+ ///
+ /// Sets the list of available printers.
+ ///
+ /// List of printer names.
+ public void SetAvailablePrinters(IEnumerable printers)
+ {
+ AvailablePrinters = printers?.ToList() ?? new List();
+
+ // If current printer is not in the list, select the first one
+ if (AvailablePrinters.Any() && !AvailablePrinters.Contains(PrintSettings.PrinterName))
+ {
+ PrintSettings.PrinterName = AvailablePrinters.First();
+ }
+ }
+
+ private void OnPrintSettingsChanged(object sender, PropertyChangedEventArgs e)
+ {
+ if (e.PropertyName == nameof(WebView2PrintSettingsModel.ScaleFactor))
+ {
+ OnPropertyChanged(nameof(ScalePercentageText));
+ }
+ else if (e.PropertyName == nameof(WebView2PrintSettingsModel.PageRanges))
+ {
+ // Update custom page range flag based on whether page ranges is empty
+ if (!string.IsNullOrWhiteSpace(PrintSettings.PageRanges))
+ {
+ IsCustomPageRange = true;
+ OnPropertyChanged(nameof(PageRangeOptionIndex));
+ }
+ }
+ }
+
+ private void UpdateDerivedProperties()
+ {
+ OnPropertyChanged(nameof(OrientationIndex));
+ OnPropertyChanged(nameof(ColorModeIndex));
+ OnPropertyChanged(nameof(CollationIndex));
+ OnPropertyChanged(nameof(DuplexIndex));
+ OnPropertyChanged(nameof(MediaSizeIndex));
+ OnPropertyChanged(nameof(PagesPerSideIndex));
+ OnPropertyChanged(nameof(PageRangeOptionIndex));
+ OnPropertyChanged(nameof(ScalePercentageText));
+
+ // Update custom page range based on current page ranges value
+ IsCustomPageRange = !string.IsNullOrWhiteSpace(PrintSettings.PageRanges);
+ }
+
+ protected virtual void OnPropertyChanged(string propertyName)
+ {
+ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
+ }
+}
\ No newline at end of file
diff --git a/Wino.Core.WinUI/Services/PrintDialogService.cs b/Wino.Core.WinUI/Services/PrintDialogService.cs
new file mode 100644
index 00000000..3fe5e548
--- /dev/null
+++ b/Wino.Core.WinUI/Services/PrintDialogService.cs
@@ -0,0 +1,93 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using System.Drawing.Printing;
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.UI.Xaml;
+using Wino.Core.Domain.Models.Printing;
+using Wino.Core.WinUI.Dialogs;
+using Wino.Core.WinUI.Interfaces;
+
+namespace Wino.Core.WinUI.Services;
+
+///
+/// Service implementation for displaying the custom print dialog and managing print settings.
+///
+public class PrintDialogService : IPrintDialogService
+{
+ ///
+ /// Shows the print dialog and returns the configured print settings.
+ ///
+ /// Initial print settings to populate the dialog with. If null, default settings will be used.
+ /// List of available printers to show in the dialog. If null or empty, the service will discover printers.
+ ///
+ /// A task that resolves to the configured WebView2PrintSettingsModel if the user clicked Print,
+ /// or null if the user cancelled the dialog.
+ ///
+ [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2070:UnrecognizedReflectionPattern",
+ Justification = "GetProperty is used for backward compatibility and gracefully handles failures")]
+ public async Task ShowPrintDialogAsync(
+ WebView2PrintSettingsModel initialSettings = null,
+ IEnumerable availablePrinters = null)
+ {
+ try
+ {
+ // Note: XamlRoot will be set by the calling code when showing the dialog
+
+ // Create the print dialog
+ var dialog = initialSettings != null
+ ? new PrintDialog(initialSettings)
+ : new PrintDialog();
+
+ // The XamlRoot will be set by the calling code when showing the dialog
+
+ // Get available printers if not provided
+ var printers = availablePrinters ?? await GetAvailablePrintersAsync();
+ dialog.SetAvailablePrinters(printers);
+
+ // Show the dialog
+ var result = await dialog.ShowAsync();
+
+ // Return the settings if user clicked Print, otherwise null
+ return result == Microsoft.UI.Xaml.Controls.ContentDialogResult.Primary
+ ? dialog.PrintSettings
+ : null;
+ }
+ catch (Exception ex)
+ {
+ // Log the exception if logging is available
+ System.Diagnostics.Debug.WriteLine($"Error showing print dialog: {ex.Message}");
+ return null;
+ }
+ }
+
+ ///
+ /// Gets the list of available printers on the system.
+ ///
+ /// A task that resolves to a list of available printer names.
+ public async Task> GetAvailablePrintersAsync()
+ {
+ return await Task.Run(() =>
+ {
+ try
+ {
+ var printers = new List();
+
+ // Get all installed printers using System.Drawing.Printing
+ foreach (string printerName in PrinterSettings.InstalledPrinters)
+ {
+ printers.Add(printerName);
+ }
+
+ return printers.AsEnumerable();
+ }
+ catch (Exception ex)
+ {
+ // Log the exception if logging is available
+ System.Diagnostics.Debug.WriteLine($"Error getting available printers: {ex.Message}");
+ return Enumerable.Empty();
+ }
+ });
+ }
+}
\ No newline at end of file
diff --git a/Wino.Core.WinUI/Services/PrintService.cs b/Wino.Core.WinUI/Services/PrintService.cs
index 92add32d..f55a9916 100644
--- a/Wino.Core.WinUI/Services/PrintService.cs
+++ b/Wino.Core.WinUI/Services/PrintService.cs
@@ -21,6 +21,7 @@ namespace Wino.Core.WinUI.Services;
/// HTML file is saved as PDF to temporary location.
/// Then PDF is loaded as PdfDocument and printed using CanvasBitmap for each page.
///
+
public class PrintService : IPrintService
{
private TaskCompletionSource _taskCompletionSource;