Add selectable image library option and refactor processing
Introduce UI option to choose between System.Graphics and ImageSharp for image processing. Update DataModel and MainForm for robust binding and synchronization. Rewrite ImageCreatorAlternate to use ImageSharp for core operations and GDI+ for overlays. Remove test buttons, add radio group for library selection. Update project dependencies to support new features and modernize image handling.
This commit is contained in:
parent
e48c0d266b
commit
63751af18d
7 changed files with 474 additions and 62 deletions
|
|
@ -397,6 +397,50 @@ namespace ImageCatalog_2
|
|||
}
|
||||
}
|
||||
|
||||
// Image library selection (UI radio buttons bind to the boolean helpers)
|
||||
private string _imageLibrary = "System.Graphics";
|
||||
|
||||
/// <summary>
|
||||
/// The selected image processing library. Possible values: "System.Graphics" or "ImageSharp".
|
||||
/// This value is mirrored into PicSettings.ImageCreatorProvider so the runtime mapper picks the implementation.
|
||||
/// </summary>
|
||||
public string ImageLibrary
|
||||
{
|
||||
get => _imageLibrary;
|
||||
set
|
||||
{
|
||||
if (_imageLibrary == value) return;
|
||||
_imageLibrary = value;
|
||||
// Reflect selection into PicSettings so mapper can resolve at runtime
|
||||
_picSettings.ImageCreatorProvider = string.Equals(value, "ImageSharp", StringComparison.OrdinalIgnoreCase)
|
||||
? "ALTERNATE"
|
||||
: "Sharp";
|
||||
NotifyPropertyChanged();
|
||||
NotifyPropertyChanged(nameof(UseSystemGraphics));
|
||||
NotifyPropertyChanged(nameof(UseImageSharp));
|
||||
}
|
||||
}
|
||||
|
||||
public bool UseSystemGraphics
|
||||
{
|
||||
get => string.Equals(ImageLibrary, "System.Graphics", StringComparison.OrdinalIgnoreCase);
|
||||
set
|
||||
{
|
||||
if (value) ImageLibrary = "System.Graphics";
|
||||
NotifyPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public bool UseImageSharp
|
||||
{
|
||||
get => string.Equals(ImageLibrary, "ImageSharp", StringComparison.OrdinalIgnoreCase);
|
||||
set
|
||||
{
|
||||
if (value) ImageLibrary = "ImageSharp";
|
||||
NotifyPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
// Folder division settings
|
||||
private int _filesPerFolder = 99;
|
||||
public int FilesPerFolder
|
||||
|
|
|
|||
75
imagecatalog/MainForm.Designer.cs
generated
75
imagecatalog/MainForm.Designer.cs
generated
|
|
@ -45,8 +45,6 @@ namespace ImageCatalog
|
|||
Label43 = new Label();
|
||||
TabControl1 = new TabControl();
|
||||
TabPage5 = new TabPage();
|
||||
button1 = new Button();
|
||||
btnTest = new Button();
|
||||
GroupBox11 = new GroupBox();
|
||||
numericUpDown2 = new NumericUpDown();
|
||||
numericUpDown1 = new NumericUpDown();
|
||||
|
|
@ -183,6 +181,9 @@ namespace ImageCatalog
|
|||
_btnCreaCatalogoAsync = new Button();
|
||||
timer1 = new System.Windows.Forms.Timer(components);
|
||||
dataModelBindingSource1 = new BindingSource(components);
|
||||
groupBox12 = new GroupBox();
|
||||
rdbLibrary1 = new RadioButton();
|
||||
rdbLibrary2 = new RadioButton();
|
||||
((System.ComponentModel.ISupportInitialize)bindingSource1).BeginInit();
|
||||
((System.ComponentModel.ISupportInitialize)dataModelBindingSource).BeginInit();
|
||||
TabControl1.SuspendLayout();
|
||||
|
|
@ -211,6 +212,7 @@ namespace ImageCatalog
|
|||
((System.ComponentModel.ISupportInitialize)_PictureBox1).BeginInit();
|
||||
((System.ComponentModel.ISupportInitialize)PictureBox3).BeginInit();
|
||||
((System.ComponentModel.ISupportInitialize)dataModelBindingSource1).BeginInit();
|
||||
groupBox12.SuspendLayout();
|
||||
SuspendLayout();
|
||||
//
|
||||
// ProgressBar1
|
||||
|
|
@ -270,8 +272,7 @@ namespace ImageCatalog
|
|||
//
|
||||
// TabPage5
|
||||
//
|
||||
TabPage5.Controls.Add(button1);
|
||||
TabPage5.Controls.Add(btnTest);
|
||||
TabPage5.Controls.Add(groupBox12);
|
||||
TabPage5.Controls.Add(GroupBox11);
|
||||
TabPage5.Controls.Add(GroupBox3);
|
||||
TabPage5.Controls.Add(GroupBox8);
|
||||
|
|
@ -285,28 +286,6 @@ namespace ImageCatalog
|
|||
TabPage5.Text = "Generale";
|
||||
TabPage5.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// button1
|
||||
//
|
||||
button1.DataBindings.Add(new Binding("Command", bindingSource1, "AsyncTestCommand", true));
|
||||
button1.Location = new Point(751, 720);
|
||||
button1.Margin = new Padding(5);
|
||||
button1.Name = "button1";
|
||||
button1.Size = new Size(141, 43);
|
||||
button1.TabIndex = 50;
|
||||
button1.Text = "Test Async";
|
||||
button1.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// btnTest
|
||||
//
|
||||
btnTest.DataBindings.Add(new Binding("Command", bindingSource1, "TestCommand", true));
|
||||
btnTest.Location = new Point(487, 708);
|
||||
btnTest.Margin = new Padding(5);
|
||||
btnTest.Name = "btnTest";
|
||||
btnTest.Size = new Size(141, 43);
|
||||
btnTest.TabIndex = 49;
|
||||
btnTest.Text = "Test";
|
||||
btnTest.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// GroupBox11
|
||||
//
|
||||
GroupBox11.Controls.Add(numericUpDown2);
|
||||
|
|
@ -1750,6 +1729,7 @@ namespace ImageCatalog
|
|||
//
|
||||
// versionLabel
|
||||
//
|
||||
versionLabel.DataBindings.Add(new Binding("Text", bindingSource1, "AppVersion", true));
|
||||
versionLabel.Location = new Point(1182, 873);
|
||||
versionLabel.Margin = new Padding(6, 0, 6, 0);
|
||||
versionLabel.Name = "versionLabel";
|
||||
|
|
@ -1757,7 +1737,6 @@ namespace ImageCatalog
|
|||
versionLabel.TabIndex = 62;
|
||||
versionLabel.Text = "Versione 2.2 2021";
|
||||
versionLabel.TextAlign = ContentAlignment.MiddleRight;
|
||||
versionLabel.DataBindings.Add(new Binding("Text", bindingSource1, "AppVersion", true));
|
||||
//
|
||||
// _Button7
|
||||
//
|
||||
|
|
@ -1863,6 +1842,41 @@ namespace ImageCatalog
|
|||
//
|
||||
dataModelBindingSource1.DataSource = typeof(ImageCatalog_2.DataModel);
|
||||
//
|
||||
// groupBox12
|
||||
//
|
||||
groupBox12.Controls.Add(rdbLibrary2);
|
||||
groupBox12.Controls.Add(rdbLibrary1);
|
||||
groupBox12.Location = new Point(405, 625);
|
||||
groupBox12.Name = "groupBox12";
|
||||
groupBox12.Size = new Size(350, 175);
|
||||
groupBox12.TabIndex = 49;
|
||||
groupBox12.TabStop = false;
|
||||
groupBox12.Text = "Libreria Manipolazione Grafica";
|
||||
//
|
||||
// rdbLibrary1
|
||||
//
|
||||
rdbLibrary1.AutoSize = true;
|
||||
rdbLibrary1.Location = new Point(12, 37);
|
||||
rdbLibrary1.Name = "rdbLibrary1";
|
||||
rdbLibrary1.Size = new Size(188, 34);
|
||||
rdbLibrary1.TabIndex = 0;
|
||||
rdbLibrary1.TabStop = true;
|
||||
rdbLibrary1.Text = "System.Graphics";
|
||||
rdbLibrary1.DataBindings.Add(new Binding("Checked", bindingSource1, "UseSystemGraphics", true, DataSourceUpdateMode.OnPropertyChanged));
|
||||
rdbLibrary1.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// rdbLibrary2
|
||||
//
|
||||
rdbLibrary2.AutoSize = true;
|
||||
rdbLibrary2.Location = new Point(12, 77);
|
||||
rdbLibrary2.Name = "rdbLibrary2";
|
||||
rdbLibrary2.Size = new Size(149, 34);
|
||||
rdbLibrary2.TabIndex = 1;
|
||||
rdbLibrary2.TabStop = true;
|
||||
rdbLibrary2.Text = "ImageSharp";
|
||||
rdbLibrary2.DataBindings.Add(new Binding("Checked", bindingSource1, "UseImageSharp", true, DataSourceUpdateMode.OnPropertyChanged));
|
||||
rdbLibrary2.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// MainForm
|
||||
//
|
||||
AutoScaleDimensions = new SizeF(12F, 30F);
|
||||
|
|
@ -1929,6 +1943,8 @@ namespace ImageCatalog
|
|||
((System.ComponentModel.ISupportInitialize)_PictureBox1).EndInit();
|
||||
((System.ComponentModel.ISupportInitialize)PictureBox3).EndInit();
|
||||
((System.ComponentModel.ISupportInitialize)dataModelBindingSource1).EndInit();
|
||||
groupBox12.ResumeLayout(false);
|
||||
groupBox12.PerformLayout();
|
||||
ResumeLayout(false);
|
||||
PerformLayout();
|
||||
}
|
||||
|
|
@ -2275,12 +2291,13 @@ namespace ImageCatalog
|
|||
private BindingSource dataModelBindingSource;
|
||||
private BindingSource dataModelBindingSource1;
|
||||
private BindingSource bindingSource1;
|
||||
private Button btnTest;
|
||||
private Button button1;
|
||||
private NumericUpDown numericUpDown1;
|
||||
private NumericUpDown numericUpDown2;
|
||||
private Button btnOpenDestFolder;
|
||||
private Button btnOpenSourceFolder;
|
||||
private GroupBox groupBox12;
|
||||
private RadioButton rdbLibrary2;
|
||||
private RadioButton rdbLibrary1;
|
||||
|
||||
internal Button btnCreaCatalogoAsync
|
||||
{
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ using ImageCatalog_2.Commands;
|
|||
using ImageCatalog_2.Services;
|
||||
using MaddoShared;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace ImageCatalog;
|
||||
|
||||
|
|
@ -30,6 +29,8 @@ public partial class MainForm
|
|||
|
||||
private readonly ParametriSetup _parametriSetup;
|
||||
private readonly PicSettings _picSettings;
|
||||
// Prevent re-entrant updates between UI events and model PropertyChanged handling
|
||||
private bool _suppressRadioUpdates = false;
|
||||
|
||||
public MainForm(DataModel model, ImageCreationStuff imageCreationStuff, PicSettings picSettings,
|
||||
ParametriSetup parametriSetup, ILogger<MainForm> logger)
|
||||
|
|
@ -42,11 +43,44 @@ public partial class MainForm
|
|||
_logger.LogDebug("Start");
|
||||
|
||||
InitializeComponent();
|
||||
|
||||
// Set this form as the control for thread marshalling in the DataModel
|
||||
Model.SetControl(this);
|
||||
|
||||
BindControls();
|
||||
// Set this form as the control for thread marshalling in the DataModel
|
||||
Model.SetControl(this);
|
||||
|
||||
// Ensure the designer data bindings have a concrete DataSource immediately so
|
||||
// that UI controls (radio buttons) reflect the ViewModel state and propagate
|
||||
// user changes back to the ViewModel.
|
||||
bindingSource1.DataSource = Model;
|
||||
|
||||
BindControls();
|
||||
|
||||
// The designer originally bound the radio buttons to boolean helpers on the ViewModel.
|
||||
// Those two separate bindings can fight with each other. Clear designer bindings and
|
||||
// wire explicit Click handlers that update the single authoritative property
|
||||
// `Model.ImageLibrary`. Also keep a PropertyChanged listener to reflect external
|
||||
// changes back into the radio buttons.
|
||||
rdbLibrary1.DataBindings.Clear();
|
||||
rdbLibrary2.DataBindings.Clear();
|
||||
|
||||
// Initialize radio state from model
|
||||
rdbLibrary1.Checked = Model.UseSystemGraphics;
|
||||
rdbLibrary2.Checked = Model.UseImageSharp;
|
||||
|
||||
// Use Click handlers (not CheckedChanged) to avoid competing binding updates
|
||||
rdbLibrary1.Click += (_, _) =>
|
||||
{
|
||||
if (_suppressRadioUpdates) return;
|
||||
if (Model.ImageLibrary != "System.Graphics")
|
||||
Model.ImageLibrary = "System.Graphics";
|
||||
};
|
||||
rdbLibrary2.Click += (_, _) =>
|
||||
{
|
||||
if (_suppressRadioUpdates) return;
|
||||
if (Model.ImageLibrary != "ImageSharp")
|
||||
Model.ImageLibrary = "ImageSharp";
|
||||
};
|
||||
|
||||
// Watch for model changes so we can reflect external updates
|
||||
Model.PropertyChanged += Model_PropertyChanged;
|
||||
|
||||
// Save user preferences on form close instead of immediately when dialogs are used
|
||||
this.FormClosing += MainForm_FormClosing;
|
||||
|
|
@ -58,17 +92,56 @@ public partial class MainForm
|
|||
// Version label is data-bound to DataModel.AppVersion; DataModel is populated with the version via DI
|
||||
}
|
||||
|
||||
protected void BindControls()
|
||||
private void RdbLibrary_CheckedChanged(object? sender, EventArgs e)
|
||||
{
|
||||
// Bind buttons to ViewModel commands using command binding
|
||||
_btnCreaCatalogoAsync.BindCommand(Model.ProcessImagesCommand);
|
||||
button1.BindCommand(Model.ProcessImagesCommand);
|
||||
_Button2.BindCommand(Model.SelectSourceFolderCommand);
|
||||
_Button3.BindCommand(Model.SelectDestinationFolderCommand);
|
||||
_Button4.BindCommand(Model.SelectLogoFileCommand);
|
||||
_Button5.BindCommand(Model.SaveSettingsCommand);
|
||||
_Button6.BindCommand(Model.LoadSettingsCommand);
|
||||
_Button8.BindCommand(Model.SelectColorCommand);
|
||||
// Keep behavior simple: when a radio button becomes checked, update the ViewModel
|
||||
// so that the designer binding and PicSettings stay in sync.
|
||||
if (sender is RadioButton rb && rb.Checked)
|
||||
{
|
||||
_logger?.LogDebug("Radio library changed: {RadioName}", rb.Name);
|
||||
if (rb == rdbLibrary2)
|
||||
{
|
||||
Model.ImageLibrary = "ImageSharp";
|
||||
}
|
||||
else if (rb == rdbLibrary1)
|
||||
{
|
||||
Model.ImageLibrary = "System.Graphics";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Model_PropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)
|
||||
{
|
||||
if (e.PropertyName is null) return;
|
||||
if (e.PropertyName == nameof(Model.ImageLibrary) || e.PropertyName == nameof(Model.UseImageSharp) || e.PropertyName == nameof(Model.UseSystemGraphics))
|
||||
{
|
||||
_logger?.LogDebug("Model property changed: {Property} => ImageLibrary={ImageLibrary}, PicSettings.Provider={Provider}", e.PropertyName, Model.ImageLibrary, _picSettings.ImageCreatorProvider);
|
||||
|
||||
// Reflect authoritative model value into the radio buttons in a thread-safe, re-entrancy-safe way
|
||||
try
|
||||
{
|
||||
_suppressRadioUpdates = true;
|
||||
rdbLibrary1.Checked = Model.UseSystemGraphics;
|
||||
rdbLibrary2.Checked = Model.UseImageSharp;
|
||||
}
|
||||
finally
|
||||
{
|
||||
_suppressRadioUpdates = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void BindControls()
|
||||
{
|
||||
// Bind buttons to ViewModel commands using command binding
|
||||
_btnCreaCatalogoAsync.BindCommand(Model.ProcessImagesCommand);
|
||||
// Note: `button1` control does not exist in the designer. Use the primary create button only.
|
||||
_Button2.BindCommand(Model.SelectSourceFolderCommand);
|
||||
_Button3.BindCommand(Model.SelectDestinationFolderCommand);
|
||||
_Button4.BindCommand(Model.SelectLogoFileCommand);
|
||||
_Button5.BindCommand(Model.SaveSettingsCommand);
|
||||
_Button6.BindCommand(Model.LoadSettingsCommand);
|
||||
_Button8.BindCommand(Model.SelectColorCommand);
|
||||
|
||||
// Subscribe to ViewModel events for UI dialogs (these need UI context)
|
||||
Model.SelectSourceFolderRequested += OnSelectSourceFolderRequested;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue