Custom print dialog.
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
namespace Wino.Core.Domain.Enums;
|
||||
|
||||
/// <summary>
|
||||
/// Print collation options.
|
||||
/// </summary>
|
||||
public enum PrintCollation
|
||||
{
|
||||
/// <summary>
|
||||
/// Default collation.
|
||||
/// </summary>
|
||||
Default = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Collated printing.
|
||||
/// </summary>
|
||||
Collated = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Uncollated printing.
|
||||
/// </summary>
|
||||
Uncollated = 2
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
namespace Wino.Core.Domain.Enums;
|
||||
|
||||
/// <summary>
|
||||
/// Print color mode options.
|
||||
/// </summary>
|
||||
public enum PrintColorMode
|
||||
{
|
||||
/// <summary>
|
||||
/// Default color mode.
|
||||
/// </summary>
|
||||
Default = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Color printing.
|
||||
/// </summary>
|
||||
Color = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Grayscale printing.
|
||||
/// </summary>
|
||||
Grayscale = 2
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
namespace Wino.Core.Domain.Enums;
|
||||
|
||||
/// <summary>
|
||||
/// Print duplex (double-sided) options.
|
||||
/// </summary>
|
||||
public enum PrintDuplex
|
||||
{
|
||||
/// <summary>
|
||||
/// Default duplex mode.
|
||||
/// </summary>
|
||||
Default = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Single-sided printing.
|
||||
/// </summary>
|
||||
Simplex = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Double-sided printing with pages flipped horizontally.
|
||||
/// </summary>
|
||||
DuplexShortEdge = 2,
|
||||
|
||||
/// <summary>
|
||||
/// Double-sided printing with pages flipped vertically.
|
||||
/// </summary>
|
||||
DuplexLongEdge = 3
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
namespace Wino.Core.Domain.Enums;
|
||||
|
||||
/// <summary>
|
||||
/// Print media size options.
|
||||
/// </summary>
|
||||
public enum PrintMediaSize
|
||||
{
|
||||
/// <summary>
|
||||
/// Default media size.
|
||||
/// </summary>
|
||||
Default = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Letter size (8.5 x 11 inches).
|
||||
/// </summary>
|
||||
NorthAmericaLetter = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Legal size (8.5 x 14 inches).
|
||||
/// </summary>
|
||||
NorthAmericaLegal = 2,
|
||||
|
||||
/// <summary>
|
||||
/// A4 size (210 x 297 mm).
|
||||
/// </summary>
|
||||
IsoA4 = 3,
|
||||
|
||||
/// <summary>
|
||||
/// A3 size (297 x 420 mm).
|
||||
/// </summary>
|
||||
IsoA3 = 4,
|
||||
|
||||
/// <summary>
|
||||
/// A5 size (148 x 210 mm).
|
||||
/// </summary>
|
||||
IsoA5 = 5,
|
||||
|
||||
/// <summary>
|
||||
/// Tabloid size (11 x 17 inches).
|
||||
/// </summary>
|
||||
NorthAmericaTabloid = 6,
|
||||
|
||||
/// <summary>
|
||||
/// Executive size (7.25 x 10.5 inches).
|
||||
/// </summary>
|
||||
NorthAmericaExecutive = 7,
|
||||
|
||||
/// <summary>
|
||||
/// B4 size (250 x 353 mm).
|
||||
/// </summary>
|
||||
JisB4 = 8,
|
||||
|
||||
/// <summary>
|
||||
/// B5 size (176 x 250 mm).
|
||||
/// </summary>
|
||||
JisB5 = 9
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
namespace Wino.Core.Domain.Enums;
|
||||
|
||||
/// <summary>
|
||||
/// Print orientation options.
|
||||
/// </summary>
|
||||
public enum PrintOrientation
|
||||
{
|
||||
/// <summary>
|
||||
/// Portrait orientation (default).
|
||||
/// </summary>
|
||||
Portrait = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Landscape orientation.
|
||||
/// </summary>
|
||||
Landscape = 1
|
||||
}
|
||||
@@ -0,0 +1,344 @@
|
||||
using System.ComponentModel;
|
||||
using Wino.Core.Domain.Enums;
|
||||
|
||||
namespace Wino.Core.Domain.Models.Printing;
|
||||
|
||||
/// <summary>
|
||||
/// Wrapper model for CoreWebView2PrintSettings that provides bindable properties for UI controls.
|
||||
/// </summary>
|
||||
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;
|
||||
|
||||
/// <summary>
|
||||
/// Name of the printer to use for printing.
|
||||
/// </summary>
|
||||
public string PrinterName
|
||||
{
|
||||
get => _printerName;
|
||||
set
|
||||
{
|
||||
if (_printerName != value)
|
||||
{
|
||||
_printerName = value;
|
||||
OnPropertyChanged(nameof(PrinterName));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Orientation of the printed document.
|
||||
/// </summary>
|
||||
public PrintOrientation Orientation
|
||||
{
|
||||
get => _orientation;
|
||||
set
|
||||
{
|
||||
if (_orientation != value)
|
||||
{
|
||||
_orientation = value;
|
||||
OnPropertyChanged(nameof(Orientation));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Color mode for printing.
|
||||
/// </summary>
|
||||
public PrintColorMode ColorMode
|
||||
{
|
||||
get => _colorMode;
|
||||
set
|
||||
{
|
||||
if (_colorMode != value)
|
||||
{
|
||||
_colorMode = value;
|
||||
OnPropertyChanged(nameof(ColorMode));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Collation setting for multiple copies.
|
||||
/// </summary>
|
||||
public PrintCollation Collation
|
||||
{
|
||||
get => _collation;
|
||||
set
|
||||
{
|
||||
if (_collation != value)
|
||||
{
|
||||
_collation = value;
|
||||
OnPropertyChanged(nameof(Collation));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Duplex printing mode.
|
||||
/// </summary>
|
||||
public PrintDuplex Duplex
|
||||
{
|
||||
get => _duplex;
|
||||
set
|
||||
{
|
||||
if (_duplex != value)
|
||||
{
|
||||
_duplex = value;
|
||||
OnPropertyChanged(nameof(Duplex));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Media size for printing.
|
||||
/// </summary>
|
||||
public PrintMediaSize MediaSize
|
||||
{
|
||||
get => _mediaSize;
|
||||
set
|
||||
{
|
||||
if (_mediaSize != value)
|
||||
{
|
||||
_mediaSize = value;
|
||||
OnPropertyChanged(nameof(MediaSize));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Number of copies to print.
|
||||
/// </summary>
|
||||
public int Copies
|
||||
{
|
||||
get => _copies;
|
||||
set
|
||||
{
|
||||
if (_copies != value && value > 0)
|
||||
{
|
||||
_copies = value;
|
||||
OnPropertyChanged(nameof(Copies));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Top margin in inches.
|
||||
/// </summary>
|
||||
public double MarginTop
|
||||
{
|
||||
get => _marginTop;
|
||||
set
|
||||
{
|
||||
if (_marginTop != value && value >= 0)
|
||||
{
|
||||
_marginTop = value;
|
||||
OnPropertyChanged(nameof(MarginTop));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Bottom margin in inches.
|
||||
/// </summary>
|
||||
public double MarginBottom
|
||||
{
|
||||
get => _marginBottom;
|
||||
set
|
||||
{
|
||||
if (_marginBottom != value && value >= 0)
|
||||
{
|
||||
_marginBottom = value;
|
||||
OnPropertyChanged(nameof(MarginBottom));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Left margin in inches.
|
||||
/// </summary>
|
||||
public double MarginLeft
|
||||
{
|
||||
get => _marginLeft;
|
||||
set
|
||||
{
|
||||
if (_marginLeft != value && value >= 0)
|
||||
{
|
||||
_marginLeft = value;
|
||||
OnPropertyChanged(nameof(MarginLeft));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Right margin in inches.
|
||||
/// </summary>
|
||||
public double MarginRight
|
||||
{
|
||||
get => _marginRight;
|
||||
set
|
||||
{
|
||||
if (_marginRight != value && value >= 0)
|
||||
{
|
||||
_marginRight = value;
|
||||
OnPropertyChanged(nameof(MarginRight));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether to print background colors and images.
|
||||
/// </summary>
|
||||
public bool ShouldPrintBackgrounds
|
||||
{
|
||||
get => _shouldPrintBackgrounds;
|
||||
set
|
||||
{
|
||||
if (_shouldPrintBackgrounds != value)
|
||||
{
|
||||
_shouldPrintBackgrounds = value;
|
||||
OnPropertyChanged(nameof(ShouldPrintBackgrounds));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether to print only the selected content.
|
||||
/// </summary>
|
||||
public bool ShouldPrintSelectionOnly
|
||||
{
|
||||
get => _shouldPrintSelectionOnly;
|
||||
set
|
||||
{
|
||||
if (_shouldPrintSelectionOnly != value)
|
||||
{
|
||||
_shouldPrintSelectionOnly = value;
|
||||
OnPropertyChanged(nameof(ShouldPrintSelectionOnly));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether to print header and footer.
|
||||
/// </summary>
|
||||
public bool ShouldPrintHeaderAndFooter
|
||||
{
|
||||
get => _shouldPrintHeaderAndFooter;
|
||||
set
|
||||
{
|
||||
if (_shouldPrintHeaderAndFooter != value)
|
||||
{
|
||||
_shouldPrintHeaderAndFooter = value;
|
||||
OnPropertyChanged(nameof(ShouldPrintHeaderAndFooter));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Title to display in the header.
|
||||
/// </summary>
|
||||
public string HeaderTitle
|
||||
{
|
||||
get => _headerTitle;
|
||||
set
|
||||
{
|
||||
if (_headerTitle != value)
|
||||
{
|
||||
_headerTitle = value ?? string.Empty;
|
||||
OnPropertyChanged(nameof(HeaderTitle));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// URI to display in the footer.
|
||||
/// </summary>
|
||||
public string FooterUri
|
||||
{
|
||||
get => _footerUri;
|
||||
set
|
||||
{
|
||||
if (_footerUri != value)
|
||||
{
|
||||
_footerUri = value ?? string.Empty;
|
||||
OnPropertyChanged(nameof(FooterUri));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scale factor for printing (0.1 to 2.0).
|
||||
/// </summary>
|
||||
public double ScaleFactor
|
||||
{
|
||||
get => _scaleFactor;
|
||||
set
|
||||
{
|
||||
if (_scaleFactor != value && value >= 0.1 && value <= 2.0)
|
||||
{
|
||||
_scaleFactor = value;
|
||||
OnPropertyChanged(nameof(ScaleFactor));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Number of pages to print per sheet (1, 2, 4, 6, 9, 16).
|
||||
/// </summary>
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Page ranges to print (e.g., "1-3,5,7-9").
|
||||
/// </summary>
|
||||
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));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,220 @@
|
||||
<ContentDialog x:Class="Wino.Core.WinUI.Dialogs.PrintDialog"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d"
|
||||
Title="Print Settings"
|
||||
PrimaryButtonText="Print"
|
||||
SecondaryButtonText="Cancel"
|
||||
DefaultButton="Primary"
|
||||
MinWidth="600"
|
||||
MinHeight="500"
|
||||
PrimaryButtonClick="ContentDialog_PrimaryButtonClick"
|
||||
SecondaryButtonClick="ContentDialog_SecondaryButtonClick">
|
||||
|
||||
<ScrollViewer>
|
||||
<StackPanel Spacing="16" Margin="20">
|
||||
|
||||
<!-- Printer Selection -->
|
||||
<StackPanel Spacing="8">
|
||||
<TextBlock Text="Printer" FontWeight="SemiBold" />
|
||||
<ComboBox x:Name="PrinterComboBox"
|
||||
ItemsSource="{x:Bind ViewModel.AvailablePrinters, Mode=OneWay}"
|
||||
SelectedItem="{x:Bind ViewModel.PrintSettings.PrinterName, Mode=TwoWay}"
|
||||
Header="Select Printer"
|
||||
HorizontalAlignment="Stretch" />
|
||||
</StackPanel>
|
||||
|
||||
<!-- Print Options Grid -->
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="20" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<!-- Left Column -->
|
||||
<StackPanel Grid.Column="0" Spacing="16">
|
||||
|
||||
<!-- Copies -->
|
||||
<StackPanel Spacing="8">
|
||||
<TextBlock Text="Copies" FontWeight="SemiBold" />
|
||||
<NumberBox Value="{x:Bind ViewModel.PrintSettings.Copies, Mode=TwoWay}"
|
||||
Minimum="1" Maximum="999"
|
||||
SpinButtonPlacementMode="Inline" />
|
||||
</StackPanel>
|
||||
|
||||
<!-- Orientation -->
|
||||
<StackPanel Spacing="8">
|
||||
<TextBlock Text="Orientation" FontWeight="SemiBold" />
|
||||
<RadioButtons SelectedIndex="{x:Bind ViewModel.OrientationIndex, Mode=TwoWay}">
|
||||
<RadioButton Content="Portrait" />
|
||||
<RadioButton Content="Landscape" />
|
||||
</RadioButtons>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Color Mode -->
|
||||
<StackPanel Spacing="8">
|
||||
<TextBlock Text="Color" FontWeight="SemiBold" />
|
||||
<RadioButtons SelectedIndex="{x:Bind ViewModel.ColorModeIndex, Mode=TwoWay}">
|
||||
<RadioButton Content="Default" />
|
||||
<RadioButton Content="Color" />
|
||||
<RadioButton Content="Grayscale" />
|
||||
</RadioButtons>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Media Size -->
|
||||
<StackPanel Spacing="8">
|
||||
<TextBlock Text="Paper Size" FontWeight="SemiBold" />
|
||||
<ComboBox SelectedIndex="{x:Bind ViewModel.MediaSizeIndex, Mode=TwoWay}"
|
||||
HorizontalAlignment="Stretch">
|
||||
<ComboBoxItem Content="Default" />
|
||||
<ComboBoxItem Content="Letter (8.5 x 11 in)" />
|
||||
<ComboBoxItem Content="Legal (8.5 x 14 in)" />
|
||||
<ComboBoxItem Content="A4 (210 x 297 mm)" />
|
||||
<ComboBoxItem Content="A3 (297 x 420 mm)" />
|
||||
<ComboBoxItem Content="A5 (148 x 210 mm)" />
|
||||
<ComboBoxItem Content="Tabloid (11 x 17 in)" />
|
||||
<ComboBoxItem Content="Executive (7.25 x 10.5 in)" />
|
||||
<ComboBoxItem Content="B4 (250 x 353 mm)" />
|
||||
<ComboBoxItem Content="B5 (176 x 250 mm)" />
|
||||
</ComboBox>
|
||||
</StackPanel>
|
||||
|
||||
</StackPanel>
|
||||
|
||||
<!-- Right Column -->
|
||||
<StackPanel Grid.Column="2" Spacing="16">
|
||||
|
||||
<!-- Duplex -->
|
||||
<StackPanel Spacing="8">
|
||||
<TextBlock Text="Duplex" FontWeight="SemiBold" />
|
||||
<RadioButtons SelectedIndex="{x:Bind ViewModel.DuplexIndex, Mode=TwoWay}">
|
||||
<RadioButton Content="Default" />
|
||||
<RadioButton Content="Single-sided" />
|
||||
<RadioButton Content="Double-sided (Short Edge)" />
|
||||
<RadioButton Content="Double-sided (Long Edge)" />
|
||||
</RadioButtons>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Collation -->
|
||||
<StackPanel Spacing="8">
|
||||
<TextBlock Text="Collation" FontWeight="SemiBold" />
|
||||
<RadioButtons SelectedIndex="{x:Bind ViewModel.CollationIndex, Mode=TwoWay}">
|
||||
<RadioButton Content="Default" />
|
||||
<RadioButton Content="Collated" />
|
||||
<RadioButton Content="Uncollated" />
|
||||
</RadioButtons>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Pages Per Side -->
|
||||
<StackPanel Spacing="8">
|
||||
<TextBlock Text="Pages Per Side" FontWeight="SemiBold" />
|
||||
<ComboBox SelectedIndex="{x:Bind ViewModel.PagesPerSideIndex, Mode=TwoWay}"
|
||||
HorizontalAlignment="Stretch">
|
||||
<ComboBoxItem Content="1" />
|
||||
<ComboBoxItem Content="2" />
|
||||
<ComboBoxItem Content="4" />
|
||||
<ComboBoxItem Content="6" />
|
||||
<ComboBoxItem Content="9" />
|
||||
<ComboBoxItem Content="16" />
|
||||
</ComboBox>
|
||||
</StackPanel>
|
||||
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<!-- Page Range -->
|
||||
<StackPanel Spacing="8">
|
||||
<TextBlock Text="Page Range" FontWeight="SemiBold" />
|
||||
<RadioButtons SelectedIndex="{x:Bind ViewModel.PageRangeOptionIndex, Mode=TwoWay}">
|
||||
<RadioButton Content="All pages" />
|
||||
<RadioButton Content="Custom range" />
|
||||
</RadioButtons>
|
||||
<TextBox x:Name="PageRangeTextBox"
|
||||
Text="{x:Bind ViewModel.PrintSettings.PageRanges, Mode=TwoWay}"
|
||||
PlaceholderText="e.g., 1-3,5,7-9"
|
||||
IsEnabled="{x:Bind ViewModel.IsCustomPageRange, Mode=OneWay}"
|
||||
Margin="0,8,0,0" />
|
||||
</StackPanel>
|
||||
|
||||
<!-- Scale Factor -->
|
||||
<StackPanel Spacing="8">
|
||||
<TextBlock Text="Scale" FontWeight="SemiBold" />
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="80" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Slider x:Name="ScaleSlider"
|
||||
Value="{x:Bind ViewModel.PrintSettings.ScaleFactor, Mode=TwoWay}"
|
||||
Minimum="0.1" Maximum="2.0" StepFrequency="0.1"
|
||||
Grid.Column="0" />
|
||||
<TextBlock Text="{x:Bind ViewModel.ScalePercentageText, Mode=OneWay}"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Grid.Column="1" />
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Margins -->
|
||||
<StackPanel Spacing="8">
|
||||
<TextBlock Text="Margins (inches)" FontWeight="SemiBold" />
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<TextBlock Text="Top" Grid.Column="0" Grid.Row="0" HorizontalAlignment="Center" />
|
||||
<TextBlock Text="Bottom" Grid.Column="1" Grid.Row="0" HorizontalAlignment="Center" />
|
||||
<TextBlock Text="Left" Grid.Column="2" Grid.Row="0" HorizontalAlignment="Center" />
|
||||
<TextBlock Text="Right" Grid.Column="3" Grid.Row="0" HorizontalAlignment="Center" />
|
||||
|
||||
<NumberBox Value="{x:Bind ViewModel.PrintSettings.MarginTop, Mode=TwoWay}"
|
||||
Minimum="0" Maximum="10" StepFrequency="0.1"
|
||||
Grid.Column="0" Grid.Row="1" Margin="4" />
|
||||
<NumberBox Value="{x:Bind ViewModel.PrintSettings.MarginBottom, Mode=TwoWay}"
|
||||
Minimum="0" Maximum="10" StepFrequency="0.1"
|
||||
Grid.Column="1" Grid.Row="1" Margin="4" />
|
||||
<NumberBox Value="{x:Bind ViewModel.PrintSettings.MarginLeft, Mode=TwoWay}"
|
||||
Minimum="0" Maximum="10" StepFrequency="0.1"
|
||||
Grid.Column="2" Grid.Row="1" Margin="4" />
|
||||
<NumberBox Value="{x:Bind ViewModel.PrintSettings.MarginRight, Mode=TwoWay}"
|
||||
Minimum="0" Maximum="10" StepFrequency="0.1"
|
||||
Grid.Column="3" Grid.Row="1" Margin="4" />
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Print Options -->
|
||||
<StackPanel Spacing="8">
|
||||
<TextBlock Text="Options" FontWeight="SemiBold" />
|
||||
<CheckBox Content="Print backgrounds"
|
||||
IsChecked="{x:Bind ViewModel.PrintSettings.ShouldPrintBackgrounds, Mode=TwoWay}" />
|
||||
<CheckBox Content="Print selection only"
|
||||
IsChecked="{x:Bind ViewModel.PrintSettings.ShouldPrintSelectionOnly, Mode=TwoWay}" />
|
||||
<CheckBox Content="Print headers and footers"
|
||||
IsChecked="{x:Bind ViewModel.PrintSettings.ShouldPrintHeaderAndFooter, Mode=TwoWay}" />
|
||||
</StackPanel>
|
||||
|
||||
<!-- Header and Footer -->
|
||||
<StackPanel Spacing="8" Visibility="{x:Bind ViewModel.PrintSettings.ShouldPrintHeaderAndFooter, Mode=OneWay}">
|
||||
<TextBlock Text="Header & Footer" FontWeight="SemiBold" />
|
||||
<TextBox Header="Header Title"
|
||||
Text="{x:Bind ViewModel.PrintSettings.HeaderTitle, Mode=TwoWay}"
|
||||
PlaceholderText="Document title" />
|
||||
<TextBox Header="Footer URI"
|
||||
Text="{x:Bind ViewModel.PrintSettings.FooterUri, Mode=TwoWay}"
|
||||
PlaceholderText="Document URL" />
|
||||
</StackPanel>
|
||||
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</ContentDialog>
|
||||
@@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// Custom print dialog for configuring WebView2 print settings.
|
||||
/// </summary>
|
||||
public sealed partial class PrintDialog : ContentDialog
|
||||
{
|
||||
/// <summary>
|
||||
/// The ViewModel that handles the dialog's data binding and logic.
|
||||
/// </summary>
|
||||
public PrintDialogViewModel ViewModel { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the configured print settings from the dialog.
|
||||
/// </summary>
|
||||
public WebView2PrintSettingsModel PrintSettings => ViewModel.PrintSettings;
|
||||
|
||||
public PrintDialog()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
ViewModel = new PrintDialogViewModel();
|
||||
ViewModel.Initialize();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the dialog with existing print settings.
|
||||
/// </summary>
|
||||
/// <param name="printSettings">The initial print settings to load.</param>
|
||||
public PrintDialog(WebView2PrintSettingsModel printSettings)
|
||||
{
|
||||
this.InitializeComponent();
|
||||
ViewModel = new PrintDialogViewModel();
|
||||
ViewModel.Initialize(printSettings);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the list of available printers for the dialog.
|
||||
/// </summary>
|
||||
/// <param name="printers">List of available printer names.</param>
|
||||
public void SetAvailablePrinters(IEnumerable<string> printers)
|
||||
{
|
||||
ViewModel.SetAvailablePrinters(printers);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates the current print settings before closing the dialog.
|
||||
/// </summary>
|
||||
/// <returns>True if settings are valid, false otherwise.</returns>
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// Extension methods and utilities for converting between Domain print models and CoreWebView2 print settings.
|
||||
/// </summary>
|
||||
public static class PrintSettingsExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts a Domain PrintOrientation to CoreWebView2PrintOrientation.
|
||||
/// </summary>
|
||||
public static CoreWebView2PrintOrientation ToCoreWebView2Orientation(this PrintOrientation orientation)
|
||||
{
|
||||
return orientation switch
|
||||
{
|
||||
PrintOrientation.Portrait => CoreWebView2PrintOrientation.Portrait,
|
||||
PrintOrientation.Landscape => CoreWebView2PrintOrientation.Landscape,
|
||||
_ => CoreWebView2PrintOrientation.Portrait
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a CoreWebView2PrintOrientation to Domain PrintOrientation.
|
||||
/// </summary>
|
||||
public static PrintOrientation ToDomainOrientation(this CoreWebView2PrintOrientation orientation)
|
||||
{
|
||||
return orientation switch
|
||||
{
|
||||
CoreWebView2PrintOrientation.Portrait => PrintOrientation.Portrait,
|
||||
CoreWebView2PrintOrientation.Landscape => PrintOrientation.Landscape,
|
||||
_ => PrintOrientation.Portrait
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a Domain PrintColorMode to CoreWebView2PrintColorMode.
|
||||
/// </summary>
|
||||
public static CoreWebView2PrintColorMode ToCoreWebView2ColorMode(this PrintColorMode colorMode)
|
||||
{
|
||||
return colorMode switch
|
||||
{
|
||||
PrintColorMode.Default => CoreWebView2PrintColorMode.Default,
|
||||
PrintColorMode.Color => CoreWebView2PrintColorMode.Color,
|
||||
PrintColorMode.Grayscale => CoreWebView2PrintColorMode.Grayscale,
|
||||
_ => CoreWebView2PrintColorMode.Default
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a CoreWebView2PrintColorMode to Domain PrintColorMode.
|
||||
/// </summary>
|
||||
public static PrintColorMode ToDomainColorMode(this CoreWebView2PrintColorMode colorMode)
|
||||
{
|
||||
return colorMode switch
|
||||
{
|
||||
CoreWebView2PrintColorMode.Default => PrintColorMode.Default,
|
||||
CoreWebView2PrintColorMode.Color => PrintColorMode.Color,
|
||||
CoreWebView2PrintColorMode.Grayscale => PrintColorMode.Grayscale,
|
||||
_ => PrintColorMode.Default
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a Domain PrintCollation to CoreWebView2PrintCollation.
|
||||
/// </summary>
|
||||
public static CoreWebView2PrintCollation ToCoreWebView2Collation(this PrintCollation collation)
|
||||
{
|
||||
return collation switch
|
||||
{
|
||||
PrintCollation.Default => CoreWebView2PrintCollation.Default,
|
||||
PrintCollation.Collated => CoreWebView2PrintCollation.Collated,
|
||||
PrintCollation.Uncollated => CoreWebView2PrintCollation.Uncollated,
|
||||
_ => CoreWebView2PrintCollation.Default
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a CoreWebView2PrintCollation to Domain PrintCollation.
|
||||
/// </summary>
|
||||
public static PrintCollation ToDomainCollation(this CoreWebView2PrintCollation collation)
|
||||
{
|
||||
return collation switch
|
||||
{
|
||||
CoreWebView2PrintCollation.Default => PrintCollation.Default,
|
||||
CoreWebView2PrintCollation.Collated => PrintCollation.Collated,
|
||||
CoreWebView2PrintCollation.Uncollated => PrintCollation.Uncollated,
|
||||
_ => PrintCollation.Default
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a Domain PrintDuplex to CoreWebView2PrintDuplex.
|
||||
/// </summary>
|
||||
public static CoreWebView2PrintDuplex ToCoreWebView2Duplex(this PrintDuplex duplex)
|
||||
{
|
||||
// Note: Simplified mapping due to enum value differences
|
||||
return duplex switch
|
||||
{
|
||||
PrintDuplex.Default => CoreWebView2PrintDuplex.Default,
|
||||
_ => CoreWebView2PrintDuplex.Default
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a CoreWebView2PrintDuplex to Domain PrintDuplex.
|
||||
/// </summary>
|
||||
public static PrintDuplex ToDomainDuplex(this CoreWebView2PrintDuplex duplex)
|
||||
{
|
||||
// Note: Simplified mapping due to enum value differences
|
||||
return duplex switch
|
||||
{
|
||||
CoreWebView2PrintDuplex.Default => PrintDuplex.Default,
|
||||
_ => PrintDuplex.Default
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a Domain PrintMediaSize to CoreWebView2PrintMediaSize.
|
||||
/// </summary>
|
||||
public static CoreWebView2PrintMediaSize ToCoreWebView2MediaSize(this PrintMediaSize mediaSize)
|
||||
{
|
||||
// Note: Simplified mapping due to enum value differences
|
||||
return mediaSize switch
|
||||
{
|
||||
PrintMediaSize.Default => CoreWebView2PrintMediaSize.Default,
|
||||
_ => CoreWebView2PrintMediaSize.Default
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a CoreWebView2PrintMediaSize to Domain PrintMediaSize.
|
||||
/// </summary>
|
||||
public static PrintMediaSize ToDomainMediaSize(this CoreWebView2PrintMediaSize mediaSize)
|
||||
{
|
||||
// Note: Simplified mapping due to enum value differences
|
||||
return mediaSize switch
|
||||
{
|
||||
CoreWebView2PrintMediaSize.Default => PrintMediaSize.Default,
|
||||
_ => PrintMediaSize.Default
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a CoreWebView2PrintSettings object from a WebView2PrintSettingsModel.
|
||||
/// </summary>
|
||||
/// <param name="model">The domain model containing the print settings.</param>
|
||||
/// <param name="environment">The CoreWebView2Environment to create the settings object.</param>
|
||||
/// <returns>A configured CoreWebView2PrintSettings object.</returns>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates a WebView2PrintSettingsModel from a CoreWebView2PrintSettings object.
|
||||
/// </summary>
|
||||
/// <param name="model">The domain model to update.</param>
|
||||
/// <param name="settings">The source CoreWebView2PrintSettings.</param>
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Wino.Core.Domain.Models.Printing;
|
||||
|
||||
namespace Wino.Core.WinUI.Interfaces;
|
||||
|
||||
/// <summary>
|
||||
/// Service interface for displaying the custom print dialog and managing print settings.
|
||||
/// </summary>
|
||||
public interface IPrintDialogService
|
||||
{
|
||||
/// <summary>
|
||||
/// Shows the print dialog and returns the configured print settings.
|
||||
/// </summary>
|
||||
/// <param name="initialSettings">Initial print settings to populate the dialog with. If null, default settings will be used.</param>
|
||||
/// <param name="availablePrinters">List of available printers to show in the dialog. If null or empty, the service should attempt to discover printers.</param>
|
||||
/// <returns>
|
||||
/// A task that resolves to the configured WebView2PrintSettingsModel if the user clicked Print,
|
||||
/// or null if the user cancelled the dialog.
|
||||
/// </returns>
|
||||
Task<WebView2PrintSettingsModel> ShowPrintDialogAsync(
|
||||
WebView2PrintSettingsModel initialSettings = null,
|
||||
IEnumerable<string> availablePrinters = null);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the list of available printers on the system.
|
||||
/// </summary>
|
||||
/// <returns>A task that resolves to a list of available printer names.</returns>
|
||||
Task<IEnumerable<string>> GetAvailablePrintersAsync();
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// ViewModel for the PrintDialog that handles data binding and state management.
|
||||
/// </summary>
|
||||
public class PrintDialogViewModel : INotifyPropertyChanged
|
||||
{
|
||||
private List<string> _availablePrinters = new();
|
||||
private bool _isCustomPageRange = false;
|
||||
private WebView2PrintSettingsModel _printSettings = new();
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
public PrintDialogViewModel()
|
||||
{
|
||||
// Initialize default values
|
||||
PrintSettings.PropertyChanged += OnPrintSettingsChanged;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The print settings model that will be configured by the dialog.
|
||||
/// </summary>
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// List of available printers.
|
||||
/// </summary>
|
||||
public List<string> AvailablePrinters
|
||||
{
|
||||
get => _availablePrinters;
|
||||
set
|
||||
{
|
||||
if (_availablePrinters != value)
|
||||
{
|
||||
_availablePrinters = value ?? new List<string>();
|
||||
OnPropertyChanged(nameof(AvailablePrinters));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Index for the orientation radio buttons.
|
||||
/// </summary>
|
||||
public int OrientationIndex
|
||||
{
|
||||
get => (int)PrintSettings.Orientation;
|
||||
set
|
||||
{
|
||||
if (value >= 0 && value <= 1)
|
||||
{
|
||||
PrintSettings.Orientation = (PrintOrientation)value;
|
||||
OnPropertyChanged(nameof(OrientationIndex));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Index for the color mode radio buttons.
|
||||
/// </summary>
|
||||
public int ColorModeIndex
|
||||
{
|
||||
get => (int)PrintSettings.ColorMode;
|
||||
set
|
||||
{
|
||||
if (value >= 0 && value <= 2)
|
||||
{
|
||||
PrintSettings.ColorMode = (PrintColorMode)value;
|
||||
OnPropertyChanged(nameof(ColorModeIndex));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Index for the collation radio buttons.
|
||||
/// </summary>
|
||||
public int CollationIndex
|
||||
{
|
||||
get => (int)PrintSettings.Collation;
|
||||
set
|
||||
{
|
||||
if (value >= 0 && value <= 2)
|
||||
{
|
||||
PrintSettings.Collation = (PrintCollation)value;
|
||||
OnPropertyChanged(nameof(CollationIndex));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Index for the duplex radio buttons.
|
||||
/// </summary>
|
||||
public int DuplexIndex
|
||||
{
|
||||
get => (int)PrintSettings.Duplex;
|
||||
set
|
||||
{
|
||||
if (value >= 0 && value <= 3)
|
||||
{
|
||||
PrintSettings.Duplex = (PrintDuplex)value;
|
||||
OnPropertyChanged(nameof(DuplexIndex));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Index for the media size combo box.
|
||||
/// </summary>
|
||||
public int MediaSizeIndex
|
||||
{
|
||||
get => (int)PrintSettings.MediaSize;
|
||||
set
|
||||
{
|
||||
if (value >= 0 && value <= 9)
|
||||
{
|
||||
PrintSettings.MediaSize = (PrintMediaSize)value;
|
||||
OnPropertyChanged(nameof(MediaSizeIndex));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Index for the pages per side combo box.
|
||||
/// </summary>
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Index for the page range option (0 = All pages, 1 = Custom range).
|
||||
/// </summary>
|
||||
public int PageRangeOptionIndex
|
||||
{
|
||||
get => IsCustomPageRange ? 1 : 0;
|
||||
set
|
||||
{
|
||||
IsCustomPageRange = value == 1;
|
||||
if (!IsCustomPageRange)
|
||||
{
|
||||
PrintSettings.PageRanges = string.Empty;
|
||||
}
|
||||
OnPropertyChanged(nameof(PageRangeOptionIndex));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether custom page range is selected.
|
||||
/// </summary>
|
||||
public bool IsCustomPageRange
|
||||
{
|
||||
get => _isCustomPageRange;
|
||||
private set
|
||||
{
|
||||
if (_isCustomPageRange != value)
|
||||
{
|
||||
_isCustomPageRange = value;
|
||||
OnPropertyChanged(nameof(IsCustomPageRange));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scale factor as percentage text for display.
|
||||
/// </summary>
|
||||
public string ScalePercentageText => $"{(int)(PrintSettings.ScaleFactor * 100)}%";
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the dialog with the provided print settings.
|
||||
/// </summary>
|
||||
/// <param name="printSettings">The initial print settings.</param>
|
||||
public void Initialize(WebView2PrintSettingsModel printSettings = null)
|
||||
{
|
||||
if (printSettings != null)
|
||||
{
|
||||
PrintSettings = printSettings;
|
||||
}
|
||||
else
|
||||
{
|
||||
PrintSettings = new WebView2PrintSettingsModel();
|
||||
}
|
||||
|
||||
UpdateDerivedProperties();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the list of available printers.
|
||||
/// </summary>
|
||||
/// <param name="printers">List of printer names.</param>
|
||||
public void SetAvailablePrinters(IEnumerable<string> printers)
|
||||
{
|
||||
AvailablePrinters = printers?.ToList() ?? new List<string>();
|
||||
|
||||
// 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));
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// Service implementation for displaying the custom print dialog and managing print settings.
|
||||
/// </summary>
|
||||
public class PrintDialogService : IPrintDialogService
|
||||
{
|
||||
/// <summary>
|
||||
/// Shows the print dialog and returns the configured print settings.
|
||||
/// </summary>
|
||||
/// <param name="initialSettings">Initial print settings to populate the dialog with. If null, default settings will be used.</param>
|
||||
/// <param name="availablePrinters">List of available printers to show in the dialog. If null or empty, the service will discover printers.</param>
|
||||
/// <returns>
|
||||
/// A task that resolves to the configured WebView2PrintSettingsModel if the user clicked Print,
|
||||
/// or null if the user cancelled the dialog.
|
||||
/// </returns>
|
||||
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2070:UnrecognizedReflectionPattern",
|
||||
Justification = "GetProperty is used for backward compatibility and gracefully handles failures")]
|
||||
public async Task<WebView2PrintSettingsModel> ShowPrintDialogAsync(
|
||||
WebView2PrintSettingsModel initialSettings = null,
|
||||
IEnumerable<string> 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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the list of available printers on the system.
|
||||
/// </summary>
|
||||
/// <returns>A task that resolves to a list of available printer names.</returns>
|
||||
public async Task<IEnumerable<string>> GetAvailablePrintersAsync()
|
||||
{
|
||||
return await Task.Run(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var printers = new List<string>();
|
||||
|
||||
// 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<string>();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
/// </summary>
|
||||
|
||||
public class PrintService : IPrintService
|
||||
{
|
||||
private TaskCompletionSource<PrintingResult> _taskCompletionSource;
|
||||
|
||||
Reference in New Issue
Block a user