Fixes and mapping
This commit is contained in:
parent
fc7175c2f7
commit
ba965e8266
10 changed files with 449 additions and 284 deletions
|
|
@ -96,7 +96,7 @@ namespace MaddoShared
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
logger.LogError(e, "Error in reporting update");
|
logger.LogError(e, "Error in reporting update");
|
||||||
throw;
|
// Don't rethrow - continue processing other images
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="AsyncEnumerator" Version="4.0.2" />
|
<PackageReference Include="AsyncEnumerator" Version="4.0.2" />
|
||||||
|
<PackageReference Include="AutoMapper" Version="16.0.0" />
|
||||||
<PackageReference Include="Ben.Demystifier" Version="0.4.1" />
|
<PackageReference Include="Ben.Demystifier" Version="0.4.1" />
|
||||||
<PackageReference Include="IDisposableAnalyzers" Version="4.0.8">
|
<PackageReference Include="IDisposableAnalyzers" Version="4.0.8">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
|
|
||||||
53
imagecatalog/Commands/ButtonCommandBinder.cs
Normal file
53
imagecatalog/Commands/ButtonCommandBinder.cs
Normal file
|
|
@ -0,0 +1,53 @@
|
||||||
|
using System;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using System.Windows.Input;
|
||||||
|
|
||||||
|
namespace ImageCatalog_2.Commands
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Helper class to bind WinForms Button controls to ICommand implementations
|
||||||
|
/// </summary>
|
||||||
|
public static class ButtonCommandBinder
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Binds a Button's Click event to an ICommand
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="button">The button to bind</param>
|
||||||
|
/// <param name="command">The command to execute</param>
|
||||||
|
/// <param name="commandParameter">Optional parameter to pass to the command</param>
|
||||||
|
public static void BindCommand(this Button button, ICommand command, object commandParameter = null)
|
||||||
|
{
|
||||||
|
if (button == null) throw new ArgumentNullException(nameof(button));
|
||||||
|
if (command == null) throw new ArgumentNullException(nameof(command));
|
||||||
|
|
||||||
|
// Wire up the Click event to execute the command
|
||||||
|
button.Click += (sender, e) =>
|
||||||
|
{
|
||||||
|
if (command.CanExecute(commandParameter))
|
||||||
|
{
|
||||||
|
command.Execute(commandParameter);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Wire up CanExecuteChanged to enable/disable the button
|
||||||
|
command.CanExecuteChanged += (sender, e) =>
|
||||||
|
{
|
||||||
|
button.Enabled = command.CanExecute(commandParameter);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Set initial enabled state
|
||||||
|
button.Enabled = command.CanExecute(commandParameter);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Binds multiple buttons to commands at once
|
||||||
|
/// </summary>
|
||||||
|
public static void BindCommands(params (Button button, ICommand command, object parameter)[] bindings)
|
||||||
|
{
|
||||||
|
foreach (var (button, command, parameter) in bindings)
|
||||||
|
{
|
||||||
|
button.BindCommand(command, parameter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,14 +1,19 @@
|
||||||
using ImageCatalog_2.Commands;
|
using ImageCatalog_2.Commands;
|
||||||
using ImageCatalog_2.Services;
|
using ImageCatalog_2.Services;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Drawing.Text;
|
using System.Drawing.Text;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows.Forms;
|
||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
|
using AutoMapper;
|
||||||
|
using MaddoShared;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace ImageCatalog_2
|
namespace ImageCatalog_2
|
||||||
|
|
@ -29,17 +34,25 @@ namespace ImageCatalog_2
|
||||||
private readonly ITestService _service;
|
private readonly ITestService _service;
|
||||||
private readonly ILogger<DataModel> _logger;
|
private readonly ILogger<DataModel> _logger;
|
||||||
private readonly ISettingsService _settingsService;
|
private readonly ISettingsService _settingsService;
|
||||||
|
private readonly ImageCreationStuff _imageCreationService;
|
||||||
|
private readonly PicSettings _picSettings;
|
||||||
|
private readonly IMapper _mapper;
|
||||||
|
|
||||||
// ComboBox collections
|
// ComboBox collections
|
||||||
public List<string> AvailableFonts { get; }
|
public List<string> AvailableFonts { get; }
|
||||||
public List<string> VerticalPositions { get; } = new() { "Alto", "Centro", "Basso" };
|
public List<string> VerticalPositions { get; } = new() { "Alto", "Centro", "Basso" };
|
||||||
public List<string> HorizontalAlignments { get; } = new() { "Sinistra", "Centro", "Destra" };
|
public List<string> HorizontalAlignments { get; } = new() { "Sinistra", "Centro", "Destra" };
|
||||||
|
|
||||||
public DataModel(ITestService testService, ISettingsService settingsService, ILogger<DataModel> logger)
|
public DataModel(ITestService testService, ISettingsService settingsService,
|
||||||
|
ImageCreationStuff imageCreationService, PicSettings picSettings,
|
||||||
|
IMapper mapper, ILogger<DataModel> logger)
|
||||||
{
|
{
|
||||||
_service = testService;
|
_service = testService;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_settingsService = settingsService;
|
_settingsService = settingsService;
|
||||||
|
_imageCreationService = imageCreationService;
|
||||||
|
_picSettings = picSettings;
|
||||||
|
_mapper = mapper;
|
||||||
|
|
||||||
TestCommand = new RelayCommand(Test);
|
TestCommand = new RelayCommand(Test);
|
||||||
AsyncTestCommand = new AsyncCommand(TestAsync);
|
AsyncTestCommand = new AsyncCommand(TestAsync);
|
||||||
|
|
@ -774,6 +787,67 @@ namespace ImageCatalog_2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Image processing progress and status
|
||||||
|
private string _processingStatus = "";
|
||||||
|
public string ProcessingStatus
|
||||||
|
{
|
||||||
|
get => _processingStatus;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_processingStatus = value;
|
||||||
|
NotifyPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int _processedImagesCount = 0;
|
||||||
|
public int ProcessedImagesCount
|
||||||
|
{
|
||||||
|
get => _processedImagesCount;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_processedImagesCount = value;
|
||||||
|
NotifyPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int _totalImagesCount = 0;
|
||||||
|
public int TotalImagesCount
|
||||||
|
{
|
||||||
|
get => _totalImagesCount;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_totalImagesCount = value;
|
||||||
|
NotifyPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int _progressBarValue = 0;
|
||||||
|
public int ProgressBarValue
|
||||||
|
{
|
||||||
|
get => _progressBarValue;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_progressBarValue = value;
|
||||||
|
NotifyPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int _progressBarMaximum = 100;
|
||||||
|
public int ProgressBarMaximum
|
||||||
|
{
|
||||||
|
get => _progressBarMaximum;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_progressBarMaximum = value;
|
||||||
|
NotifyPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ConcurrentBag<string> _results = new();
|
||||||
|
private int _currentAmount = 0;
|
||||||
|
private int _previousAmount = 0;
|
||||||
|
private System.Threading.Timer? _speedTimer;
|
||||||
|
|
||||||
private void Test(object parameter)
|
private void Test(object parameter)
|
||||||
{
|
{
|
||||||
Debug.WriteLine("Yep");
|
Debug.WriteLine("Yep");
|
||||||
|
|
@ -787,6 +861,123 @@ namespace ImageCatalog_2
|
||||||
|
|
||||||
private async Task ProcessImages()
|
private async Task ProcessImages()
|
||||||
{
|
{
|
||||||
|
_logger.LogInformation("Avvio elaborazione...");
|
||||||
|
UiEnabled = false;
|
||||||
|
|
||||||
|
MainToken?.Dispose();
|
||||||
|
MainToken = new CancellationTokenSource();
|
||||||
|
var token = MainToken.Token;
|
||||||
|
|
||||||
|
// Fix paths
|
||||||
|
FixPaths();
|
||||||
|
|
||||||
|
// Reset counters
|
||||||
|
ProcessingStatus = "Elaborazione in corso...";
|
||||||
|
TotalImagesCount = 0;
|
||||||
|
ProcessedImagesCount = 0;
|
||||||
|
SpeedCounter = "-f/m";
|
||||||
|
ProgressBarValue = 0;
|
||||||
|
ProgressBarMaximum = 100;
|
||||||
|
|
||||||
|
// Update PicSettings from DataModel using AutoMapper
|
||||||
|
_mapper.Map(this, _picSettings);
|
||||||
|
|
||||||
|
var imageCreationOptions = new ImageCreationStuff.Options
|
||||||
|
{
|
||||||
|
AggiornaSottodirectory = UpdateSubdirectories,
|
||||||
|
CreaSottocartelle = CreateSubfolders,
|
||||||
|
FilePerCartella = FilesPerFolder,
|
||||||
|
SuffissoCartelle = FolderSuffix,
|
||||||
|
CifreContatore = CounterDigits,
|
||||||
|
NumerazioneType = UseProgressiveNumbering ? NumerazioneType.Progressiva : NumerazioneType.Files,
|
||||||
|
SourcePath = SourcePath,
|
||||||
|
DestinationPath = DestinationPath,
|
||||||
|
MaxThreads = ThreadsCount,
|
||||||
|
ChunksSize = ChunkSize,
|
||||||
|
LinearExecution = UseSequentialProcessing
|
||||||
|
};
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_results = new ConcurrentBag<string>();
|
||||||
|
_currentAmount = 0;
|
||||||
|
_previousAmount = 0;
|
||||||
|
|
||||||
|
// Start speed timer (every minute)
|
||||||
|
_speedTimer = new System.Threading.Timer(UpdateSpeedCounter, null, TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(1));
|
||||||
|
|
||||||
|
var time = await _imageCreationService.CreaCatalogoParallel(
|
||||||
|
imageCreationOptions,
|
||||||
|
_results,
|
||||||
|
OnImageProcessed,
|
||||||
|
token);
|
||||||
|
|
||||||
|
SpeedCounter = time;
|
||||||
|
_speedTimer?.Dispose();
|
||||||
|
_speedTimer = null;
|
||||||
|
}
|
||||||
|
catch (OperationCanceledException)
|
||||||
|
{
|
||||||
|
_logger.LogInformation("Operazione Cancellata");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Errore durante l'elaborazione delle immagini");
|
||||||
|
ProcessingStatus = $"Errore: {ex.Message}";
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
MainToken?.Dispose();
|
||||||
|
MainToken = null;
|
||||||
|
_speedTimer?.Dispose();
|
||||||
|
_speedTimer = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
ProcessingStatus = "Finito";
|
||||||
|
UiEnabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateSpeedCounter(object? state)
|
||||||
|
{
|
||||||
|
_previousAmount = _currentAmount;
|
||||||
|
_currentAmount = _results.Count;
|
||||||
|
int diff = _currentAmount - _previousAmount;
|
||||||
|
SpeedCounter = $"{diff} f/m";
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnImageProcessed(object? sender, Tuple<string, int> args)
|
||||||
|
{
|
||||||
|
ProcessedImagesCount = _results.Count;
|
||||||
|
TotalImagesCount = args.Item2;
|
||||||
|
ProgressBarMaximum = args.Item2;
|
||||||
|
ProgressBarValue = _results.Count;
|
||||||
|
ProcessingStatus = args.Item1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void FixPaths()
|
||||||
|
{
|
||||||
|
SourcePath = FixPath(SourcePath);
|
||||||
|
DestinationPath = FixPath(DestinationPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
private string FixPath(string path)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(path))
|
||||||
|
{
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trim leading/trailing quotes
|
||||||
|
path = path.Trim().Trim('"');
|
||||||
|
|
||||||
|
// Normalize directory separators
|
||||||
|
path = path.Replace('/', System.IO.Path.DirectorySeparatorChar)
|
||||||
|
.Replace('\\', System.IO.Path.DirectorySeparatorChar);
|
||||||
|
|
||||||
|
// Remove trailing separators then add one back
|
||||||
|
path = path.TrimEnd(System.IO.Path.DirectorySeparatorChar) + System.IO.Path.DirectorySeparatorChar;
|
||||||
|
|
||||||
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task CancelOperation()
|
private async Task CancelOperation()
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@
|
||||||
<ProjectReference Include="..\MaddoShared\MaddoShared.csproj" />
|
<ProjectReference Include="..\MaddoShared\MaddoShared.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="AutoMapper" Version="16.0.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="10.0.2" />
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="10.0.2" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="10.0.2" />
|
<PackageReference Include="Microsoft.Extensions.Logging" Version="10.0.2" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="10.0.2" />
|
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="10.0.2" />
|
||||||
|
|
|
||||||
10
imagecatalog/MainForm.Designer.cs
generated
10
imagecatalog/MainForm.Designer.cs
generated
|
|
@ -1835,7 +1835,6 @@ namespace ImageCatalog
|
||||||
_btnCreaCatalogoAsync.TabIndex = 68;
|
_btnCreaCatalogoAsync.TabIndex = 68;
|
||||||
_btnCreaCatalogoAsync.Text = "CREA";
|
_btnCreaCatalogoAsync.Text = "CREA";
|
||||||
_btnCreaCatalogoAsync.UseVisualStyleBackColor = true;
|
_btnCreaCatalogoAsync.UseVisualStyleBackColor = true;
|
||||||
_btnCreaCatalogoAsync.Click += Button1_Click;
|
|
||||||
//
|
//
|
||||||
// dataModelBindingSource1
|
// dataModelBindingSource1
|
||||||
//
|
//
|
||||||
|
|
@ -2268,16 +2267,7 @@ namespace ImageCatalog
|
||||||
[MethodImpl(MethodImplOptions.Synchronized)]
|
[MethodImpl(MethodImplOptions.Synchronized)]
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (_btnCreaCatalogoAsync != null)
|
|
||||||
{
|
|
||||||
_btnCreaCatalogoAsync.Click -= Button1_Click;
|
|
||||||
}
|
|
||||||
|
|
||||||
_btnCreaCatalogoAsync = value;
|
_btnCreaCatalogoAsync = value;
|
||||||
if (_btnCreaCatalogoAsync != null)
|
|
||||||
{
|
|
||||||
_btnCreaCatalogoAsync.Click += Button1_Click;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,9 +13,11 @@ using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using ImageCatalog_2;
|
using ImageCatalog_2;
|
||||||
|
using ImageCatalog_2.Commands;
|
||||||
using ImageCatalog_2.Services;
|
using ImageCatalog_2.Services;
|
||||||
using MaddoShared;
|
using MaddoShared;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace ImageCatalog;
|
namespace ImageCatalog;
|
||||||
|
|
||||||
|
|
@ -25,8 +27,6 @@ public partial class MainForm
|
||||||
|
|
||||||
private readonly ILogger<MainForm> _logger;
|
private readonly ILogger<MainForm> _logger;
|
||||||
|
|
||||||
private readonly ImageCreationStuff _imageCreationService;
|
|
||||||
|
|
||||||
private readonly ParametriSetup _parametriSetup;
|
private readonly ParametriSetup _parametriSetup;
|
||||||
private readonly PicSettings _picSettings;
|
private readonly PicSettings _picSettings;
|
||||||
|
|
||||||
|
|
@ -34,7 +34,6 @@ public partial class MainForm
|
||||||
ParametriSetup parametriSetup, ILogger<MainForm> logger)
|
ParametriSetup parametriSetup, ILogger<MainForm> logger)
|
||||||
{
|
{
|
||||||
Model = model;
|
Model = model;
|
||||||
_imageCreationService = imageCreationStuff;
|
|
||||||
_parametriSetup = parametriSetup;
|
_parametriSetup = parametriSetup;
|
||||||
_picSettings = picSettings;
|
_picSettings = picSettings;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
|
|
@ -42,77 +41,37 @@ public partial class MainForm
|
||||||
_logger.LogDebug("Start");
|
_logger.LogDebug("Start");
|
||||||
|
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
|
// Set this form as the control for thread marshalling in the DataModel
|
||||||
|
Model.SetControl(this);
|
||||||
|
|
||||||
BindControls();
|
BindControls();
|
||||||
|
|
||||||
// Subscribe to DataModel events
|
var version = Assembly.GetExecutingAssembly().GetName().Version;
|
||||||
|
_Label27.Text = $"Version: {version.Major}.{version.Minor}.{version.Build}.{version.Revision}";
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void BindControls()
|
||||||
|
{
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
// Subscribe to ViewModel events for UI dialogs (these need UI context)
|
||||||
Model.SelectSourceFolderRequested += OnSelectSourceFolderRequested;
|
Model.SelectSourceFolderRequested += OnSelectSourceFolderRequested;
|
||||||
Model.SelectDestinationFolderRequested += OnSelectDestinationFolderRequested;
|
Model.SelectDestinationFolderRequested += OnSelectDestinationFolderRequested;
|
||||||
Model.SelectLogoFileRequested += OnSelectLogoFileRequested;
|
Model.SelectLogoFileRequested += OnSelectLogoFileRequested;
|
||||||
Model.SaveSettingsRequested += OnSaveSettingsRequested;
|
Model.SaveSettingsRequested += OnSaveSettingsRequested;
|
||||||
Model.LoadSettingsRequested += OnLoadSettingsRequested;
|
Model.LoadSettingsRequested += OnLoadSettingsRequested;
|
||||||
Model.SelectColorRequested += OnSelectColorRequested;
|
Model.SelectColorRequested += OnSelectColorRequested;
|
||||||
|
|
||||||
var version = Assembly.GetExecutingAssembly().GetName().Version;
|
|
||||||
_Label27.Text = $"Version: {version.Major}.{version.Minor}.{version.Build}.{version.Revision}";
|
|
||||||
|
|
||||||
_results = [];
|
|
||||||
UiUpdateEvent += OnUiUpdateEvent;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void BindControls()
|
|
||||||
{
|
|
||||||
// Wire up buttons to ViewModel commands
|
|
||||||
_Button2.Click += (s, e) => Model.SelectSourceFolderCommand.Execute(null);
|
|
||||||
_Button3.Click += (s, e) => Model.SelectDestinationFolderCommand.Execute(null);
|
|
||||||
_Button4.Click += (s, e) => Model.SelectLogoFileCommand.Execute(null);
|
|
||||||
_Button5.Click += (s, e) => Model.SaveSettingsCommand.Execute(null);
|
|
||||||
_Button6.Click += (s, e) => Model.LoadSettingsCommand.Execute(null);
|
|
||||||
_Button8.Click += (s, e) => Model.SelectColorCommand.Execute(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
private event EventHandler<Tuple<string, int>> UiUpdateEvent;
|
|
||||||
|
|
||||||
delegate void SetTextCallback(Label target, string text);
|
|
||||||
|
|
||||||
private void SetText(Label target, string text)
|
|
||||||
{
|
|
||||||
if (InvokeRequired)
|
|
||||||
{
|
|
||||||
var d = new SetTextCallback(SetText);
|
|
||||||
this.Invoke(d, new object[] { target, text });
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
target.Text = text;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private delegate void SetProgressCallback(ProgressBar target, int amount, int maximum);
|
|
||||||
|
|
||||||
private void SetProgress(ProgressBar target, int amount, int maximum)
|
|
||||||
{
|
|
||||||
if (InvokeRequired)
|
|
||||||
{
|
|
||||||
var d = new SetProgressCallback(SetProgress);
|
|
||||||
this.Invoke(d, new object[] { target, amount, maximum });
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
target.Maximum = maximum;
|
|
||||||
target.Value = amount;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnUiUpdateEvent(object sender, Tuple<string, int> args)
|
|
||||||
{
|
|
||||||
SetProgress(ProgressBar1, _results.Count, args.Item2);
|
|
||||||
SetText(Label18, _results.Count.ToString());
|
|
||||||
SetText(Label10, args.Item1);
|
|
||||||
SetText(lblFotoTotaliNum, args.Item2.ToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
private ConcurrentBag<string> _results;
|
|
||||||
|
|
||||||
private void SetDefaults()
|
private void SetDefaults()
|
||||||
{
|
{
|
||||||
// Bind ComboBoxes to Model using proper data binding
|
// Bind ComboBoxes to Model using proper data binding
|
||||||
|
|
@ -135,6 +94,19 @@ public partial class MainForm
|
||||||
ComboBox5.DataSource = new List<string> { "Alto", "Centro", "Basso" };
|
ComboBox5.DataSource = new List<string> { "Alto", "Centro", "Basso" };
|
||||||
ComboBox5.DataBindings.Add(new Binding("SelectedItem", bindingSource1, nameof(Model.LogoVerticalPosition),
|
ComboBox5.DataBindings.Add(new Binding("SelectedItem", bindingSource1, nameof(Model.LogoVerticalPosition),
|
||||||
false, DataSourceUpdateMode.OnPropertyChanged));
|
false, DataSourceUpdateMode.OnPropertyChanged));
|
||||||
|
|
||||||
|
// Bind progress bar and status labels
|
||||||
|
ProgressBar1.DataBindings.Add(new Binding("Maximum", bindingSource1, nameof(Model.ProgressBarMaximum),
|
||||||
|
false, DataSourceUpdateMode.OnPropertyChanged));
|
||||||
|
ProgressBar1.DataBindings.Add(new Binding("Value", bindingSource1, nameof(Model.ProgressBarValue),
|
||||||
|
false, DataSourceUpdateMode.OnPropertyChanged));
|
||||||
|
|
||||||
|
Label18.DataBindings.Add(new Binding("Text", bindingSource1, nameof(Model.ProcessedImagesCount),
|
||||||
|
false, DataSourceUpdateMode.OnPropertyChanged));
|
||||||
|
lblFotoTotaliNum.DataBindings.Add(new Binding("Text", bindingSource1, nameof(Model.TotalImagesCount),
|
||||||
|
false, DataSourceUpdateMode.OnPropertyChanged));
|
||||||
|
Label10.DataBindings.Add(new Binding("Text", bindingSource1, nameof(Model.ProcessingStatus),
|
||||||
|
false, DataSourceUpdateMode.OnPropertyChanged));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -147,50 +119,6 @@ public partial class MainForm
|
||||||
_logger.LogInformation("Programma Avviato");
|
_logger.LogInformation("Programma Avviato");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void FixPaths()
|
|
||||||
{
|
|
||||||
Model.SourcePath = FixPath(Model.SourcePath);
|
|
||||||
Model.DestinationPath = FixPath(Model.DestinationPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
private string FixPath(string path)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrWhiteSpace(path))
|
|
||||||
{
|
|
||||||
return string.Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Trim leading/trailing quotes
|
|
||||||
path = path.Trim().Trim('"');
|
|
||||||
|
|
||||||
// Normalize directory separators
|
|
||||||
path = path.Replace('/', Path.DirectorySeparatorChar)
|
|
||||||
.Replace('\\', Path.DirectorySeparatorChar);
|
|
||||||
|
|
||||||
// Remove trailing separators then add one back
|
|
||||||
path = path.TrimEnd(Path.DirectorySeparatorChar) + Path.DirectorySeparatorChar;
|
|
||||||
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void lockUI()
|
|
||||||
{
|
|
||||||
Model.UiEnabled = false;
|
|
||||||
//TabControl1.Enabled = false;
|
|
||||||
//Button5.Enabled = false;
|
|
||||||
//Button6.Enabled = false;
|
|
||||||
//btnCreaCatalogoAsync.Enabled = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void unlockUI()
|
|
||||||
{
|
|
||||||
Model.UiEnabled = true;
|
|
||||||
//TabControl1.Enabled = true;
|
|
||||||
//Button5.Enabled = true;
|
|
||||||
//Button6.Enabled = true;
|
|
||||||
//btnCreaCatalogoAsync.Enabled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private string CalcTime(DateTime timeStart, DateTime timeStop, int numFoto)
|
private string CalcTime(DateTime timeStart, DateTime timeStop, int numFoto)
|
||||||
{
|
{
|
||||||
long timediffH, timediffS;
|
long timediffH, timediffS;
|
||||||
|
|
@ -224,6 +152,26 @@ public partial class MainForm
|
||||||
return FixPath(dialog.SelectedPath);
|
return FixPath(dialog.SelectedPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string FixPath(string path)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(path))
|
||||||
|
{
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trim leading/trailing quotes
|
||||||
|
path = path.Trim().Trim('"');
|
||||||
|
|
||||||
|
// Normalize directory separators
|
||||||
|
path = path.Replace('/', Path.DirectorySeparatorChar)
|
||||||
|
.Replace('\\', Path.DirectorySeparatorChar);
|
||||||
|
|
||||||
|
// Remove trailing separators then add one back
|
||||||
|
path = path.TrimEnd(Path.DirectorySeparatorChar) + Path.DirectorySeparatorChar;
|
||||||
|
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
private void OnSelectSourceFolderRequested(object sender, EventArgs e)
|
private void OnSelectSourceFolderRequested(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
var dialogResult = SelectFolder(Model.SourcePath);
|
var dialogResult = SelectFolder(Model.SourcePath);
|
||||||
|
|
@ -356,76 +304,6 @@ public partial class MainForm
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetPicSettings(string SourcePath, string DestPath)
|
|
||||||
{
|
|
||||||
_picSettings.DirectorySorgente = SourcePath;
|
|
||||||
_picSettings.DirectoryDestinazione = DestPath;
|
|
||||||
|
|
||||||
// Font and text settings from Model
|
|
||||||
_picSettings.DimStandard = Model.FontSize;
|
|
||||||
_picSettings.DimStandardMiniatura = Model.FontSizeThumbnail;
|
|
||||||
_picSettings.IlFont = Model.FontName;
|
|
||||||
_picSettings.Grassetto = Model.FontBold;
|
|
||||||
_picSettings.Posizione = Model.VerticalPosition;
|
|
||||||
_picSettings.Allineamento = Model.HorizontalAlignment;
|
|
||||||
_picSettings.Trasparenza = Model.TextTransparency;
|
|
||||||
_picSettings.Margine = Model.TextMargin;
|
|
||||||
_picSettings.FontColoreRGB = ColorTranslator.FromHtml(Model.TextColorRGB);
|
|
||||||
|
|
||||||
// Thumbnail settings from Model
|
|
||||||
_picSettings.AltezzaSmall = Model.ThumbnailHeight;
|
|
||||||
_picSettings.LarghezzaSmall = Model.ThumbnailWidth;
|
|
||||||
_picSettings.Suffisso = Model.ThumbnailPrefix;
|
|
||||||
_picSettings.CreaMiniature = Model.CreateThumbnails;
|
|
||||||
_picSettings.JpegQualityMin = Model.JpegQualityThumbnail;
|
|
||||||
_picSettings.DimMin = Model.FontSizeThumbnail;
|
|
||||||
|
|
||||||
// Big photo settings from Model
|
|
||||||
_picSettings.AltezzaBig = Model.PhotoBigHeight;
|
|
||||||
_picSettings.LarghezzaBig = Model.PhotoBigWidth;
|
|
||||||
_picSettings.FotoGrandeDimOrigina = Model.KeepOriginalDimensions;
|
|
||||||
_picSettings.JpegQuality = Model.JpegQuality;
|
|
||||||
_picSettings.Codice = Model.BigPhotoSuffix;
|
|
||||||
|
|
||||||
// Logo settings from Model
|
|
||||||
_picSettings.LogoAggiungi = Model.AddLogo;
|
|
||||||
_picSettings.LogoNomeFile = Model.LogoFile;
|
|
||||||
_picSettings.LogoAltezza = Model.LogoHeight;
|
|
||||||
_picSettings.LogoLarghezza = Model.LogoWidth;
|
|
||||||
_picSettings.LogoMargine = Model.LogoMargin.ToString();
|
|
||||||
_picSettings.LogoTrasparenza = Model.LogoTransparency.ToString();
|
|
||||||
_picSettings.LogoPosizioneH = Model.LogoHorizontalPosition;
|
|
||||||
_picSettings.LogoPosizioneV = Model.LogoVerticalPosition;
|
|
||||||
|
|
||||||
// Text content from Model
|
|
||||||
_picSettings.TestoFirmaStart = Model.HorizontalText;
|
|
||||||
_picSettings.TestoFirmaStartV = Model.VerticalText;
|
|
||||||
|
|
||||||
// Vertical text settings from Model
|
|
||||||
_picSettings.DimVert = Model.VerticalTextSize;
|
|
||||||
_picSettings.MargVert = Model.VerticalTextMargin;
|
|
||||||
|
|
||||||
// Boolean flags from Model
|
|
||||||
_picSettings.UsaRotazioneAutomatica = Model.AutomaticRotation;
|
|
||||||
_picSettings.UsaForzaJpg = Model.ForceJpeg;
|
|
||||||
_picSettings.TestoNome = Model.ShowPhotoNumber;
|
|
||||||
_picSettings.NomeData = Model.ShowDate;
|
|
||||||
_picSettings.UsaOrarioTestoApplicare = Model.AddTime;
|
|
||||||
_picSettings.UsaTempoGaraTestoApplicare = Model.AddRaceTime;
|
|
||||||
_picSettings.OverwriteFiles = Model.OverwriteImages;
|
|
||||||
|
|
||||||
// Additional settings from Model
|
|
||||||
_picSettings.UsaOrarioMiniatura = Model.AddTimeToThumbnails;
|
|
||||||
_picSettings.DataPartenza = Model.RaceStartDate;
|
|
||||||
_picSettings.TestoOrario = Model.TimeLabel;
|
|
||||||
_picSettings.TestoMin = Model.ShowFileNameOnThumbnails;
|
|
||||||
|
|
||||||
// Thumbnail text options from Model
|
|
||||||
_picSettings.AggiungiScritteMiniature = Model.AddTextToThumbnails;
|
|
||||||
_picSettings.AggTempoGaraMin = Model.AddRaceTimeToThumbnails;
|
|
||||||
_picSettings.AggNumTempMin = Model.AddNumberAndTimeToThumbnails;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setLabel18Text(string text)
|
private void setLabel18Text(string text)
|
||||||
{
|
{
|
||||||
if (Label18.InvokeRequired)
|
if (Label18.InvokeRequired)
|
||||||
|
|
@ -437,99 +315,6 @@ public partial class MainForm
|
||||||
Label18.Text = text;
|
Label18.Text = text;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private NumerazioneType GetNumerazioneEnum()
|
|
||||||
{
|
|
||||||
NumerazioneType numerazioneType;
|
|
||||||
if (rdbNumProgressiva.Checked)
|
|
||||||
{
|
|
||||||
numerazioneType = NumerazioneType.Progressiva;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
numerazioneType = NumerazioneType.Files;
|
|
||||||
}
|
|
||||||
|
|
||||||
return numerazioneType;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private async void Button1_Click(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
_logger.LogInformation("Avvio elaborazione...");
|
|
||||||
lockUI();
|
|
||||||
|
|
||||||
Model.MainToken?.Dispose();
|
|
||||||
Model.MainToken = new CancellationTokenSource();
|
|
||||||
var token = Model.MainToken.Token;
|
|
||||||
|
|
||||||
// timeStart = TimeOfDay
|
|
||||||
FixPaths();
|
|
||||||
Label10.Text = "Elaborazione in corso...";
|
|
||||||
lblFotoTotaliNum.Text = "0";
|
|
||||||
Label18.Text = "0";
|
|
||||||
Model.SpeedCounter = "-f/m";
|
|
||||||
SetPicSettings(Model.SourcePath, Model.DestinationPath);
|
|
||||||
ProgressBar1.Minimum = 0;
|
|
||||||
ProgressBar1.Step = 1;
|
|
||||||
ProgressBar1.Value = 0;
|
|
||||||
|
|
||||||
var imageCreationOptions = new ImageCreationStuff.Options
|
|
||||||
{
|
|
||||||
AggiornaSottodirectory = chkAggiornaSottodirectory.Checked,
|
|
||||||
CreaSottocartelle = chkCreaSottocartelle.Checked,
|
|
||||||
FilePerCartella = int.Parse(txtFilePerCartella.Text),
|
|
||||||
SuffissoCartelle = txtSuffissoCartelle.Text,
|
|
||||||
CifreContatore = int.Parse(txtCifreContatore.Text),
|
|
||||||
NumerazioneType = GetNumerazioneEnum(),
|
|
||||||
SourcePath = Model.SourcePath,
|
|
||||||
DestinationPath = Model.DestinationPath,
|
|
||||||
MaxThreads = Model.ThreadsCount,
|
|
||||||
ChunksSize = Model.ChunkSize,
|
|
||||||
LinearExecution = rdbVecchioMetodo.Checked
|
|
||||||
};
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_results = [];
|
|
||||||
_currentAmount = 0;
|
|
||||||
_previousAmount = 0;
|
|
||||||
timer1.Tick += Timer1OnTick;
|
|
||||||
|
|
||||||
timer1.Interval = 1000 * 60;
|
|
||||||
timer1.Enabled = true;
|
|
||||||
|
|
||||||
var time =
|
|
||||||
await _imageCreationService.CreaCatalogoParallel(imageCreationOptions, _results, UiUpdateEvent, token);
|
|
||||||
Model.SpeedCounter = time;
|
|
||||||
timer1.Enabled = false;
|
|
||||||
}
|
|
||||||
catch (OperationCanceledException operationCanceledException)
|
|
||||||
{
|
|
||||||
_logger.LogInformation("Operazione Cancellata");
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
Model.MainToken?.Dispose();
|
|
||||||
Model.MainToken = null;
|
|
||||||
|
|
||||||
timer1.Tick -= Timer1OnTick;
|
|
||||||
}
|
|
||||||
|
|
||||||
Label10.Text = "Finito";
|
|
||||||
unlockUI();
|
|
||||||
}
|
|
||||||
|
|
||||||
private int _currentAmount = 0;
|
|
||||||
private int _previousAmount = 0;
|
|
||||||
|
|
||||||
private void Timer1OnTick(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
_previousAmount = _currentAmount;
|
|
||||||
_currentAmount = _results.Count;
|
|
||||||
int diff = _currentAmount - _previousAmount;
|
|
||||||
Model.SpeedCounter = $"{diff} f/m";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class PicInfo
|
public class PicInfo
|
||||||
|
|
|
||||||
94
imagecatalog/Mappings/DataModelMappingProfile.cs
Normal file
94
imagecatalog/Mappings/DataModelMappingProfile.cs
Normal file
|
|
@ -0,0 +1,94 @@
|
||||||
|
using System.Drawing;
|
||||||
|
using AutoMapper;
|
||||||
|
using MaddoShared;
|
||||||
|
|
||||||
|
namespace ImageCatalog_2.Mappings;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// AutoMapper profile for mapping between DataModel and PicSettings
|
||||||
|
/// </summary>
|
||||||
|
public class DataModelMappingProfile : Profile
|
||||||
|
{
|
||||||
|
public DataModelMappingProfile()
|
||||||
|
{
|
||||||
|
CreateMap<DataModel, PicSettings>()
|
||||||
|
// Paths
|
||||||
|
.ForMember(dest => dest.DirectorySorgente, opt => opt.MapFrom(src => src.SourcePath))
|
||||||
|
.ForMember(dest => dest.DirectoryDestinazione, opt => opt.MapFrom(src => src.DestinationPath))
|
||||||
|
|
||||||
|
// Font and text settings
|
||||||
|
.ForMember(dest => dest.DimStandard, opt => opt.MapFrom(src => src.FontSize))
|
||||||
|
.ForMember(dest => dest.DimStandardMiniatura, opt => opt.MapFrom(src => src.FontSizeThumbnail))
|
||||||
|
.ForMember(dest => dest.IlFont, opt => opt.MapFrom(src => src.FontName))
|
||||||
|
.ForMember(dest => dest.Grassetto, opt => opt.MapFrom(src => src.FontBold))
|
||||||
|
.ForMember(dest => dest.Posizione, opt => opt.MapFrom(src => src.VerticalPosition))
|
||||||
|
.ForMember(dest => dest.Allineamento, opt => opt.MapFrom(src => src.HorizontalAlignment))
|
||||||
|
.ForMember(dest => dest.Trasparenza, opt => opt.MapFrom(src => src.TextTransparency))
|
||||||
|
.ForMember(dest => dest.Margine, opt => opt.MapFrom(src => src.TextMargin))
|
||||||
|
.ForMember(dest => dest.FontColoreRGB, opt => opt.MapFrom(src => ColorTranslator.FromHtml(src.TextColorRGB)))
|
||||||
|
|
||||||
|
// Thumbnail settings
|
||||||
|
.ForMember(dest => dest.AltezzaSmall, opt => opt.MapFrom(src => src.ThumbnailHeight))
|
||||||
|
.ForMember(dest => dest.LarghezzaSmall, opt => opt.MapFrom(src => src.ThumbnailWidth))
|
||||||
|
.ForMember(dest => dest.Suffisso, opt => opt.MapFrom(src => src.ThumbnailPrefix))
|
||||||
|
.ForMember(dest => dest.CreaMiniature, opt => opt.MapFrom(src => src.CreateThumbnails))
|
||||||
|
.ForMember(dest => dest.JpegQualityMin, opt => opt.MapFrom(src => src.JpegQualityThumbnail))
|
||||||
|
.ForMember(dest => dest.DimMin, opt => opt.MapFrom(src => src.FontSizeThumbnail))
|
||||||
|
|
||||||
|
// Big photo settings
|
||||||
|
.ForMember(dest => dest.AltezzaBig, opt => opt.MapFrom(src => src.PhotoBigHeight))
|
||||||
|
.ForMember(dest => dest.LarghezzaBig, opt => opt.MapFrom(src => src.PhotoBigWidth))
|
||||||
|
.ForMember(dest => dest.FotoGrandeDimOrigina, opt => opt.MapFrom(src => src.KeepOriginalDimensions))
|
||||||
|
.ForMember(dest => dest.JpegQuality, opt => opt.MapFrom(src => src.JpegQuality))
|
||||||
|
.ForMember(dest => dest.Codice, opt => opt.MapFrom(src => src.BigPhotoSuffix))
|
||||||
|
|
||||||
|
// Logo settings
|
||||||
|
.ForMember(dest => dest.LogoAggiungi, opt => opt.MapFrom(src => src.AddLogo))
|
||||||
|
.ForMember(dest => dest.LogoNomeFile, opt => opt.MapFrom(src => src.LogoFile))
|
||||||
|
.ForMember(dest => dest.LogoAltezza, opt => opt.MapFrom(src => src.LogoHeight))
|
||||||
|
.ForMember(dest => dest.LogoLarghezza, opt => opt.MapFrom(src => src.LogoWidth))
|
||||||
|
.ForMember(dest => dest.LogoMargine, opt => opt.MapFrom(src => src.LogoMargin.ToString()))
|
||||||
|
.ForMember(dest => dest.LogoTrasparenza, opt => opt.MapFrom(src => src.LogoTransparency.ToString()))
|
||||||
|
.ForMember(dest => dest.LogoPosizioneH, opt => opt.MapFrom(src => src.LogoHorizontalPosition))
|
||||||
|
.ForMember(dest => dest.LogoPosizioneV, opt => opt.MapFrom(src => src.LogoVerticalPosition))
|
||||||
|
|
||||||
|
// Text content
|
||||||
|
.ForMember(dest => dest.TestoFirmaStart, opt => opt.MapFrom(src => src.HorizontalText))
|
||||||
|
.ForMember(dest => dest.TestoFirmaStartV, opt => opt.MapFrom(src => src.VerticalText))
|
||||||
|
|
||||||
|
// Vertical text settings
|
||||||
|
.ForMember(dest => dest.DimVert, opt => opt.MapFrom(src => src.VerticalTextSize))
|
||||||
|
.ForMember(dest => dest.MargVert, opt => opt.MapFrom(src => src.VerticalTextMargin))
|
||||||
|
|
||||||
|
// Boolean flags
|
||||||
|
.ForMember(dest => dest.UsaRotazioneAutomatica, opt => opt.MapFrom(src => src.AutomaticRotation))
|
||||||
|
.ForMember(dest => dest.UsaForzaJpg, opt => opt.MapFrom(src => src.ForceJpeg))
|
||||||
|
.ForMember(dest => dest.TestoNome, opt => opt.MapFrom(src => src.ShowPhotoNumber))
|
||||||
|
.ForMember(dest => dest.NomeData, opt => opt.MapFrom(src => src.ShowDate))
|
||||||
|
.ForMember(dest => dest.UsaOrarioTestoApplicare, opt => opt.MapFrom(src => src.AddTime))
|
||||||
|
.ForMember(dest => dest.UsaTempoGaraTestoApplicare, opt => opt.MapFrom(src => src.AddRaceTime))
|
||||||
|
.ForMember(dest => dest.OverwriteFiles, opt => opt.MapFrom(src => src.OverwriteImages))
|
||||||
|
|
||||||
|
// Additional settings
|
||||||
|
.ForMember(dest => dest.UsaOrarioMiniatura, opt => opt.MapFrom(src => src.AddTimeToThumbnails))
|
||||||
|
.ForMember(dest => dest.DataPartenza, opt => opt.MapFrom(src => src.RaceStartDate))
|
||||||
|
.ForMember(dest => dest.TestoOrario, opt => opt.MapFrom(src => src.TimeLabel))
|
||||||
|
.ForMember(dest => dest.TestoMin, opt => opt.MapFrom(src => src.ShowFileNameOnThumbnails))
|
||||||
|
|
||||||
|
// Thumbnail text options
|
||||||
|
.ForMember(dest => dest.AggiungiScritteMiniature, opt => opt.MapFrom(src => src.AddTextToThumbnails))
|
||||||
|
.ForMember(dest => dest.AggTempoGaraMin, opt => opt.MapFrom(src => src.AddRaceTimeToThumbnails))
|
||||||
|
.ForMember(dest => dest.AggNumTempMin, opt => opt.MapFrom(src => src.AddNumberAndTimeToThumbnails))
|
||||||
|
|
||||||
|
// Ignore unmapped properties
|
||||||
|
.ForMember(dest => dest.DestDir, opt => opt.Ignore())
|
||||||
|
.ForMember(dest => dest.SecretDefault, opt => opt.Ignore())
|
||||||
|
.ForMember(dest => dest.SecretBig, opt => opt.Ignore())
|
||||||
|
.ForMember(dest => dest.SecretSmall, opt => opt.Ignore())
|
||||||
|
.ForMember(dest => dest.SecretPathSmall, opt => opt.Ignore())
|
||||||
|
.ForMember(dest => dest.SecretPathBig, opt => opt.Ignore())
|
||||||
|
.ForMember(dest => dest.FotoRuotaADestra, opt => opt.Ignore())
|
||||||
|
.ForMember(dest => dest.FotoRuotaASinistra, opt => opt.Ignore())
|
||||||
|
.ForMember(dest => dest.TempMinText, opt => opt.Ignore());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3,6 +3,7 @@ using ImageCatalog;
|
||||||
using ImageCatalog_2.Services;
|
using ImageCatalog_2.Services;
|
||||||
using MaddoShared;
|
using MaddoShared;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using AutoMapper;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Logging.Abstractions;
|
using Microsoft.Extensions.Logging.Abstractions;
|
||||||
using Microsoft.Extensions.Logging.Console;
|
using Microsoft.Extensions.Logging.Console;
|
||||||
|
|
@ -79,6 +80,9 @@ static class Program
|
||||||
|
|
||||||
private static void ConfigureServices(ServiceCollection services)
|
private static void ConfigureServices(ServiceCollection services)
|
||||||
{
|
{
|
||||||
|
// Register AutoMapper (new AddAutoMapper overload — provide config and marker types)
|
||||||
|
services.AddAutoMapper(cfg => { }, typeof(Program));
|
||||||
|
|
||||||
// Register your services here
|
// Register your services here
|
||||||
services.AddTransient<ITestService, TestService>();
|
services.AddTransient<ITestService, TestService>();
|
||||||
services.AddTransient<ISettingsService, SettingsService>();
|
services.AddTransient<ISettingsService, SettingsService>();
|
||||||
|
|
|
||||||
|
|
@ -4,20 +4,66 @@ using System.ComponentModel;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
|
||||||
namespace ImageCatalog_2
|
namespace ImageCatalog_2
|
||||||
{
|
{
|
||||||
public class ViewModelBase : INotifyPropertyChanged
|
public class ViewModelBase : INotifyPropertyChanged
|
||||||
{
|
{
|
||||||
|
private readonly SynchronizationContext? _synchronizationContext;
|
||||||
|
private Control? _control;
|
||||||
|
|
||||||
|
protected ViewModelBase()
|
||||||
|
{
|
||||||
|
// Capture the synchronization context (UI thread context)
|
||||||
|
_synchronizationContext = SynchronizationContext.Current;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Set a Control to use for thread marshalling in WinForms applications.
|
||||||
|
/// This is required for proper cross-thread handling with data binding.
|
||||||
|
/// </summary>
|
||||||
|
public void SetControl(Control control)
|
||||||
|
{
|
||||||
|
_control = control;
|
||||||
|
}
|
||||||
|
|
||||||
public event PropertyChangedEventHandler? PropertyChanged;
|
public event PropertyChangedEventHandler? PropertyChanged;
|
||||||
|
|
||||||
// This method is called by the Set accessor of each property.
|
// This method is called by the Set accessor of each property.
|
||||||
// The CallerMemberName attribute that is applied to the optional propertyName
|
// The CallerMemberName attribute that is applied to the optional propertyName
|
||||||
// parameter causes the property name of the caller to be substituted as an argument.
|
// parameter causes the property name of the caller to be substituted as an argument.
|
||||||
protected void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
|
protected void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
|
||||||
{
|
{
|
||||||
if (PropertyChanged != null)
|
if (PropertyChanged == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// If we have a Control reference (WinForms), use Control.Invoke for proper marshalling
|
||||||
|
if (_control != null)
|
||||||
{
|
{
|
||||||
|
if (_control.InvokeRequired)
|
||||||
|
{
|
||||||
|
_control.Invoke(() => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Fallback to SynchronizationContext if available
|
||||||
|
else if (_synchronizationContext != null && SynchronizationContext.Current != _synchronizationContext)
|
||||||
|
{
|
||||||
|
// We're on a different thread, marshal to the UI thread
|
||||||
|
_synchronizationContext.Send(_ =>
|
||||||
|
{
|
||||||
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||||
|
}, null);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// We're already on the UI thread or no sync context available
|
||||||
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
|
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue