Custom print dialog and better message registrations
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.UI.Xaml;
|
||||
@@ -27,6 +26,16 @@ public partial class BasePage : Page, IRecipient<LanguageChanged>
|
||||
}
|
||||
|
||||
public virtual void OnLanguageChanged() { }
|
||||
|
||||
/// <summary>
|
||||
/// Register message recipients for this page. Override to register specific message types.
|
||||
/// </summary>
|
||||
protected virtual void RegisterRecipients() { }
|
||||
|
||||
/// <summary>
|
||||
/// Unregister message recipients for this page. Override to unregister specific message types.
|
||||
/// </summary>
|
||||
protected virtual void UnregisterRecipients() { }
|
||||
}
|
||||
|
||||
public abstract class BasePage<T> : BasePage where T : CoreBaseViewModel
|
||||
@@ -49,10 +58,7 @@ public abstract class BasePage<T> : BasePage where T : CoreBaseViewModel
|
||||
|
||||
private void PageLoaded(object sender, RoutedEventArgs e) => ViewModel.OnPageLoaded();
|
||||
|
||||
~BasePage()
|
||||
{
|
||||
Debug.WriteLine($"Disposed {GetType().Name}");
|
||||
}
|
||||
~BasePage() { Debug.WriteLine($"Disposed {GetType().Name}"); }
|
||||
|
||||
protected override void OnNavigatedTo(NavigationEventArgs e)
|
||||
{
|
||||
@@ -61,8 +67,8 @@ public abstract class BasePage<T> : BasePage where T : CoreBaseViewModel
|
||||
var mode = GetNavigationMode(e.NavigationMode);
|
||||
var parameter = e.Parameter;
|
||||
|
||||
WeakReferenceMessenger.Default.UnregisterAll(this);
|
||||
WeakReferenceMessenger.Default.Register<LanguageChanged>(this);
|
||||
RegisterRecipients();
|
||||
|
||||
ViewModel.OnNavigatedTo(mode, parameter);
|
||||
}
|
||||
@@ -74,7 +80,8 @@ public abstract class BasePage<T> : BasePage where T : CoreBaseViewModel
|
||||
var mode = GetNavigationMode(e.NavigationMode);
|
||||
var parameter = e.Parameter;
|
||||
|
||||
WeakReferenceMessenger.Default.UnregisterAll(this);
|
||||
WeakReferenceMessenger.Default.Unregister<LanguageChanged>(this);
|
||||
UnregisterRecipients();
|
||||
|
||||
ViewModel.OnNavigatedFrom(mode, parameter);
|
||||
|
||||
|
||||
@@ -1,220 +1,54 @@
|
||||
<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">
|
||||
<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"
|
||||
xmlns:printing="using:Wino.Core.Domain.Models.Printing"
|
||||
Title="Print Settings"
|
||||
MinWidth="400"
|
||||
MinHeight="300"
|
||||
DefaultButton="Primary"
|
||||
Loaded="PrintDialog_Loaded"
|
||||
PrimaryButtonClick="ContentDialog_PrimaryButtonClick"
|
||||
PrimaryButtonText="Print"
|
||||
SecondaryButtonClick="ContentDialog_SecondaryButtonClick"
|
||||
SecondaryButtonText="Cancel"
|
||||
Style="{StaticResource WinoDialogStyle}"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<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>
|
||||
<StackPanel Margin="20" Spacing="16">
|
||||
|
||||
<!-- Print Options Grid -->
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="20" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<!-- Printer Selection -->
|
||||
<ComboBox
|
||||
x:Name="PrinterComboBox"
|
||||
HorizontalAlignment="Stretch"
|
||||
Header="Printer"
|
||||
SelectedItem="{x:Bind PrintSettings.PrinterName, Mode=TwoWay}"
|
||||
SelectionChanged="PrinterComboBox_SelectionChanged" />
|
||||
|
||||
<!-- 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>
|
||||
<!-- Copies -->
|
||||
<NumberBox
|
||||
Header="Copies"
|
||||
Maximum="999"
|
||||
Minimum="1"
|
||||
SpinButtonPlacementMode="Inline"
|
||||
Value="{x:Bind PrintSettings.Copies, Mode=TwoWay}" />
|
||||
|
||||
<!-- 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>
|
||||
<!-- Orientation -->
|
||||
<RadioButtons
|
||||
x:Name="OrientationRadioButtons"
|
||||
Header="Orientation"
|
||||
SelectionChanged="OrientationRadio_SelectionChanged">
|
||||
<RadioButton Content="Portrait" />
|
||||
<RadioButton Content="Landscape" />
|
||||
</RadioButtons>
|
||||
|
||||
<!-- Print Options -->
|
||||
<StackPanel Spacing="8">
|
||||
<TextBlock Text="Options" />
|
||||
<CheckBox Content="Print backgrounds" IsChecked="{x:Bind PrintSettings.ShouldPrintBackgrounds, Mode=TwoWay}" />
|
||||
<CheckBox Content="Print headers and footers" IsChecked="{x:Bind PrintSettings.ShouldPrintHeaderAndFooter, Mode=TwoWay}" />
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</ContentDialog>
|
||||
</StackPanel>
|
||||
</ContentDialog>
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing.Printing;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Serilog;
|
||||
using Wino.Core.Domain.Enums;
|
||||
using Wino.Core.Domain.Models.Printing;
|
||||
using Wino.Core.WinUI.Models;
|
||||
|
||||
namespace Wino.Core.WinUI.Dialogs;
|
||||
|
||||
@@ -10,32 +14,40 @@ namespace Wino.Core.WinUI.Dialogs;
|
||||
/// </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 WebView2PrintSettingsModel PrintSettings { get; set; } = new WebView2PrintSettingsModel();
|
||||
|
||||
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)
|
||||
public PrintDialog(WebView2PrintSettingsModel printSettings = null)
|
||||
{
|
||||
if (printSettings != null) PrintSettings = printSettings;
|
||||
|
||||
this.InitializeComponent();
|
||||
ViewModel = new PrintDialogViewModel();
|
||||
ViewModel.Initialize(printSettings);
|
||||
}
|
||||
|
||||
private void PrintDialog_Loaded(object sender, Microsoft.UI.Xaml.RoutedEventArgs e) => LoadSettingsToUI(PrintSettings);
|
||||
|
||||
private void OrientationRadio_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
if (sender is RadioButtons radioButtons)
|
||||
{
|
||||
PrintSettings.Orientation = (PrintOrientation)radioButtons.SelectedIndex;
|
||||
}
|
||||
}
|
||||
|
||||
private void PrinterComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
if (sender is ComboBox comboBox && comboBox.SelectedItem != null)
|
||||
{
|
||||
PrintSettings.PrinterName = comboBox.SelectedItem.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -44,7 +56,85 @@ public sealed partial class PrintDialog : ContentDialog
|
||||
/// <param name="printers">List of available printer names.</param>
|
||||
public void SetAvailablePrinters(IEnumerable<string> printers)
|
||||
{
|
||||
ViewModel.SetAvailablePrinters(printers);
|
||||
var printerList = printers?.ToList() ?? new List<string>();
|
||||
|
||||
if (this.FindName("PrinterComboBox") is ComboBox printerComboBox)
|
||||
{
|
||||
printerComboBox.ItemsSource = printerList;
|
||||
|
||||
if (printerList.Any())
|
||||
{
|
||||
// Set to first printer or to the one in settings
|
||||
var targetPrinter = !string.IsNullOrEmpty(PrintSettings.PrinterName)
|
||||
? PrintSettings.PrinterName
|
||||
: printerList.First();
|
||||
|
||||
var index = printerList.IndexOf(targetPrinter);
|
||||
printerComboBox.SelectedIndex = index >= 0 ? index : 0;
|
||||
|
||||
// Update the settings model with the selected printer
|
||||
PrintSettings.PrinterName = printerComboBox.SelectedItem?.ToString() ?? string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads available printers asynchronously and sets them in the dialog.
|
||||
/// </summary>
|
||||
public async Task LoadAvailablePrintersAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
var printers = await Task.Run(() =>
|
||||
{
|
||||
var printerList = new List<string>();
|
||||
|
||||
// Get all installed printers using System.Drawing.Printing
|
||||
foreach (string printerName in PrinterSettings.InstalledPrinters)
|
||||
{
|
||||
printerList.Add(printerName);
|
||||
}
|
||||
|
||||
return printerList.AsEnumerable();
|
||||
});
|
||||
|
||||
SetAvailablePrinters(printers);
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
// Log the exception if logging is available
|
||||
Log.Error(ex, "Error getting available printers");
|
||||
|
||||
// Set empty list if printer discovery fails
|
||||
SetAvailablePrinters(Enumerable.Empty<string>());
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadSettingsToUI(WebView2PrintSettingsModel settings)
|
||||
{
|
||||
if (settings == null) return;
|
||||
|
||||
// Only handle orientation manually since other properties are bound via x:Bind
|
||||
if (this.FindName("OrientationRadioButtons") is RadioButtons orientationRadio)
|
||||
{
|
||||
orientationRadio.SelectedIndex = (int)settings.Orientation;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateSettingsFromUI()
|
||||
{
|
||||
// Most properties are bound via x:Bind, only handle orientation manually
|
||||
if (this.FindName("OrientationRadioButtons") is RadioButtons orientationRadio)
|
||||
{
|
||||
PrintSettings.Orientation = (PrintOrientation)orientationRadio.SelectedIndex;
|
||||
}
|
||||
|
||||
// Also update printer name from ComboBox since it uses ItemsSource binding
|
||||
if (this.FindName("PrinterComboBox") is ComboBox printerComboBox &&
|
||||
printerComboBox.SelectedItem != null)
|
||||
{
|
||||
PrintSettings.PrinterName = printerComboBox.SelectedItem.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -53,54 +143,31 @@ public sealed partial class PrintDialog : ContentDialog
|
||||
/// <returns>True if settings are valid, false otherwise.</returns>
|
||||
private bool ValidateSettings()
|
||||
{
|
||||
// Validate printer selection
|
||||
if (string.IsNullOrWhiteSpace(PrintSettings.PrinterName))
|
||||
// Check if a printer is selected
|
||||
if (this.FindName("PrinterComboBox") is ComboBox printerComboBox &&
|
||||
printerComboBox.SelectedItem == null)
|
||||
{
|
||||
// Show error message or set focus to printer selection
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate copies
|
||||
// Copies validation is handled by the bound property with validation in the model
|
||||
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)
|
||||
{
|
||||
// Update settings from UI before validation
|
||||
UpdateSettingsFromUI();
|
||||
|
||||
// Validate settings before closing
|
||||
if (!ValidateSettings())
|
||||
{
|
||||
args.Cancel = true;
|
||||
// Could show error message here
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,4 +175,4 @@ public sealed partial class PrintDialog : ContentDialog
|
||||
{
|
||||
// Cancel was clicked, no validation needed
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ public static class XamlHelpers
|
||||
public static Visibility ReverseBoolToVisibilityConverter(bool value) => value ? Visibility.Collapsed : Visibility.Visible;
|
||||
public static Visibility ReverseVisibilityConverter(Visibility visibility) => visibility == Visibility.Visible ? Visibility.Collapsed : Visibility.Visible;
|
||||
public static bool ReverseBoolConverter(bool value) => !value;
|
||||
public static bool ShouldDisplayPreview(string text) => text.Any(x => char.IsLetter(x));
|
||||
public static bool ShouldDisplayPreview(string text) => text == null ? false : text.Any(x => char.IsLetter(x));
|
||||
public static bool CountToBooleanConverter(int value) => value > 0;
|
||||
public static bool ObjectEquals(object obj1, object obj2) => object.Equals(obj1, obj2);
|
||||
public static Visibility CountToVisibilityConverter(int value) => value > 0 ? Visibility.Visible : Visibility.Collapsed;
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
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();
|
||||
}
|
||||
@@ -14,6 +14,7 @@ using Wino.Core.Domain.Enums;
|
||||
using Wino.Core.Domain.Interfaces;
|
||||
using Wino.Core.Domain.Models.Accounts;
|
||||
using Wino.Core.Domain.Models.Common;
|
||||
using Wino.Core.Domain.Models.Printing;
|
||||
using Wino.Core.WinUI.Dialogs;
|
||||
using Wino.Core.WinUI.Extensions;
|
||||
using Wino.Dialogs;
|
||||
@@ -294,4 +295,38 @@ public class DialogServiceBase : IDialogServiceBase
|
||||
|
||||
return dialog.Result;
|
||||
}
|
||||
|
||||
public async Task<WebView2PrintSettingsModel> ShowPrintDialogAsync(WebView2PrintSettingsModel initialSettings = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Create the print dialog
|
||||
var dialog = initialSettings != null
|
||||
? new PrintDialog(initialSettings)
|
||||
: new PrintDialog();
|
||||
|
||||
// Set the XamlRoot for proper display
|
||||
dialog.XamlRoot = GetXamlRoot();
|
||||
|
||||
// Get available printers asynchronously when the dialog is loaded
|
||||
dialog.Loaded += async (sender, e) =>
|
||||
{
|
||||
await dialog.LoadAvailablePrintersAsync();
|
||||
};
|
||||
|
||||
// Show the dialog
|
||||
var result = await HandleDialogPresentationAsync(dialog);
|
||||
|
||||
// Return the settings if user clicked Print, otherwise null
|
||||
return result == ContentDialogResult.Primary
|
||||
? dialog.PrintSettings
|
||||
: null;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Log the exception if logging is available
|
||||
Log.Error(ex, "Error showing print dialog");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,93 +0,0 @@
|
||||
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>();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
using Microsoft.UI.Xaml;
|
||||
using Wino.Core.WinUI;
|
||||
using Wino.Core.ViewModels;
|
||||
using Wino.Core.WinUI;
|
||||
|
||||
namespace Wino.Views.Abstract;
|
||||
|
||||
|
||||
@@ -26,9 +26,6 @@ public sealed partial class SettingsPage : SettingsPageAbstract, IRecipient<Brea
|
||||
{
|
||||
base.OnNavigatedTo(e);
|
||||
|
||||
// Re-register the breadcrumb navigation handler after base.OnNavigatedTo unregisters all handlers
|
||||
WeakReferenceMessenger.Default.Register<BreadcrumbNavigationRequested>(this);
|
||||
|
||||
SettingsFrame.Navigate(typeof(SettingOptionsPage), null, new SuppressNavigationTransitionInfo());
|
||||
|
||||
var initialRequest = new BreadcrumbNavigationRequested(Translator.MenuSettings, WinoPage.SettingOptionsPage);
|
||||
@@ -63,12 +60,23 @@ public sealed partial class SettingsPage : SettingsPageAbstract, IRecipient<Brea
|
||||
|
||||
protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
|
||||
{
|
||||
// Explicitly unregister our message handlers before base.OnNavigatingFrom calls UnregisterAll
|
||||
WeakReferenceMessenger.Default.Unregister<BreadcrumbNavigationRequested>(this);
|
||||
|
||||
base.OnNavigatingFrom(e);
|
||||
}
|
||||
|
||||
protected override void RegisterRecipients()
|
||||
{
|
||||
base.RegisterRecipients();
|
||||
|
||||
WeakReferenceMessenger.Default.Register<BreadcrumbNavigationRequested>(this);
|
||||
}
|
||||
|
||||
protected override void UnregisterRecipients()
|
||||
{
|
||||
base.UnregisterRecipients();
|
||||
|
||||
WeakReferenceMessenger.Default.Unregister<BreadcrumbNavigationRequested>(this);
|
||||
}
|
||||
|
||||
void IRecipient<BreadcrumbNavigationRequested>.Receive(BreadcrumbNavigationRequested message)
|
||||
{
|
||||
var pageType = ViewModel.NavigationService.GetPageType(message.PageType);
|
||||
|
||||
Reference in New Issue
Block a user