diff --git a/imagecatalog/MainForm.cs b/imagecatalog/MainForm.cs index d31a157..43940cb 100644 --- a/imagecatalog/MainForm.cs +++ b/imagecatalog/MainForm.cs @@ -48,6 +48,9 @@ public partial class MainForm BindControls(); + // Save user preferences on form close instead of immediately when dialogs are used + this.FormClosing += MainForm_FormClosing; + // Wire up 'Open folder in Explorer' buttons btnOpenSourceFolder.Click += BtnOpenSourceFolder_Click; btnOpenDestFolder.Click += BtnOpenDestFolder_Click; @@ -194,10 +197,17 @@ public partial class MainForm private void OnSelectSourceFolderRequested(object sender, EventArgs e) { - var dialogResult = SelectFolder(Model.SourcePath); + // Prefer model value; if empty fall back to last-used value stored in user prefs + var starting = !string.IsNullOrWhiteSpace(Model.SourcePath) + ? Model.SourcePath + : _parametriSetup.LeggiParametroString("LastSourceFolder"); + + var dialogResult = SelectFolder(starting); if (!string.IsNullOrWhiteSpace(dialogResult)) { Model.SourcePath = dialogResult; + _parametriSetup.AggiornaParametro("LastSourceFolder", dialogResult); + _parametriSetup.SalvaParametriSetup(); } } @@ -254,10 +264,16 @@ public partial class MainForm private void OnSelectDestinationFolderRequested(object sender, EventArgs e) { - var dialogResult = SelectFolder(Model.DestinationPath); + var starting = !string.IsNullOrWhiteSpace(Model.DestinationPath) + ? Model.DestinationPath + : _parametriSetup.LeggiParametroString("LastDestinationFolder"); + + var dialogResult = SelectFolder(starting); if (!string.IsNullOrWhiteSpace(dialogResult)) { Model.DestinationPath = dialogResult; + _parametriSetup.AggiornaParametro("LastDestinationFolder", dialogResult); + _parametriSetup.SalvaParametriSetup(); } } @@ -265,15 +281,36 @@ public partial class MainForm { var dialog = new OpenFileDialog(); dialog.Filter = "Image Files|*.jpg;*.jpeg;*.png;*.bmp;*.gif"; - if (Model.LogoFile.Length > 0) + if (!string.IsNullOrWhiteSpace(Model.LogoFile)) { dialog.FileName = Model.LogoFile; } + else + { + var lastLogoFolder = _parametriSetup.LeggiParametroString("LastLogoFolder"); + if (!string.IsNullOrWhiteSpace(lastLogoFolder) && Directory.Exists(lastLogoFolder)) + { + dialog.InitialDirectory = lastLogoFolder; + } + } if (dialog.ShowDialog() == DialogResult.OK) { Model.LogoFile = dialog.FileName; UpdateLogoPictureBox(Model.LogoFile); + try + { + var folder = Path.GetDirectoryName(dialog.FileName) ?? string.Empty; + if (!string.IsNullOrWhiteSpace(folder)) + { + _parametriSetup.AggiornaParametro("LastLogoFolder", folder); + _parametriSetup.SalvaParametriSetup(); + } + } + catch + { + // ignore preferences save failures + } } } @@ -285,11 +322,28 @@ public partial class MainForm FilterIndex = 0, RestoreDirectory = true }; - + var lastSettings = _parametriSetup.LeggiParametroString("LastSettingsFolder"); + if (!string.IsNullOrWhiteSpace(lastSettings) && Directory.Exists(lastSettings)) + saveDialog.InitialDirectory = lastSettings; + if (saveDialog.ShowDialog() != DialogResult.OK) return; await Model.SaveSettingsToFileAsync(saveDialog.FileName); Text = "Image Catalog - " + Path.GetFileName(saveDialog.FileName); + + try + { + var folder = Path.GetDirectoryName(saveDialog.FileName) ?? string.Empty; + if (!string.IsNullOrWhiteSpace(folder)) + { + _parametriSetup.AggiornaParametro("LastSettingsFolder", folder); + _parametriSetup.SalvaParametriSetup(); + } + } + catch + { + // ignore + } } private async void OnLoadSettingsRequested(object sender, string e) @@ -301,6 +355,10 @@ public partial class MainForm RestoreDirectory = true }; + var lastSettings = _parametriSetup.LeggiParametroString("LastSettingsFolder"); + if (!string.IsNullOrWhiteSpace(lastSettings) && Directory.Exists(lastSettings)) + openDialog.InitialDirectory = lastSettings; + if (openDialog.ShowDialog() != DialogResult.OK) return; try @@ -318,6 +376,20 @@ public partial class MainForm Text = "Image Catalog - " + Path.GetFileName(openDialog.FileName); + try + { + var folder = Path.GetDirectoryName(openDialog.FileName) ?? string.Empty; + if (!string.IsNullOrWhiteSpace(folder)) + { + _parametriSetup.AggiornaParametro("LastSettingsFolder", folder); + _parametriSetup.SalvaParametriSetup(); + } + } + catch + { + // ignore preferences save failures + } + _logger.LogInformation($"Settings loaded successfully from {openDialog.FileName}"); } catch (Exception ex) @@ -327,6 +399,24 @@ public partial class MainForm } } + private void MainForm_FormClosing(object? sender, FormClosingEventArgs e) + { + try + { + // Persist last-used dialogs paths (user preferences) + // These keys are managed independently from settings files + // and must be saved when the form closes. + _parametriSetup.AggiornaParametro("LastSourceFolder", Model.SourcePath ?? string.Empty); + _parametriSetup.AggiornaParametro("LastDestinationFolder", Model.DestinationPath ?? string.Empty); + _parametriSetup.AggiornaParametro("LastLogoFolder", Path.GetDirectoryName(Model.LogoFile ?? string.Empty) ?? string.Empty); + _parametriSetup.SalvaParametriSetup(); + } + catch (Exception ex) + { + _logger?.LogWarning(ex, "Failed to save user preferences on exit"); + } + } + private void OnSelectColorRequested(object sender, EventArgs e) { var colorDialog = new ColorDialog diff --git a/imagecatalog/Program.cs b/imagecatalog/Program.cs index 2a5e2b2..ea8f2aa 100644 --- a/imagecatalog/Program.cs +++ b/imagecatalog/Program.cs @@ -92,7 +92,10 @@ static class Program services.AddTransient(); services.AddTransient(); - services.AddSingleton(); + // Register a ParametriSetup singleton that persists user preferences in LocalApplicationData + var userPrefsPath = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), + "ImageCatalog", "userprefs.xml"); + services.AddSingleton(new ParametriSetup(userPrefsPath)); services.AddSingleton(); // Register your forms diff --git a/imagecatalog/Services/SettingsService.cs b/imagecatalog/Services/SettingsService.cs index 3b0a630..8a92333 100644 --- a/imagecatalog/Services/SettingsService.cs +++ b/imagecatalog/Services/SettingsService.cs @@ -24,40 +24,41 @@ namespace ImageCatalog_2.Services public Task SaveSettingsAsync(string filePath, object settings) { + // Use a dedicated ParametriSetup instance for the target settings file so the injected + // user preferences store is not modified. This keeps user prefs (singleton) intact. return Task.Run(() => { - _parametriSetup.NomeFileSetup = filePath; - + var fileParams = new ParametriSetup(filePath); + // Convert ViewModel to DTO var dto = ViewModelToDto(settings); - + // Use reflection on DTO properties with XmlElement attribute var properties = typeof(SettingsDto).GetProperties(BindingFlags.Public | BindingFlags.Instance); foreach (var prop in properties) { - // Get the XmlElement attribute to determine the XML property name var xmlAttr = prop.GetCustomAttribute(); if (xmlAttr == null) - continue; // Skip properties without XmlElement attribute - + continue; + var xmlName = xmlAttr.ElementName; var value = prop.GetValue(dto); - - _parametriSetup.AggiornaParametro(xmlName, value); + + fileParams.AggiornaParametro(xmlName, value); } - _parametriSetup.SalvaParametriSetup(); + fileParams.SalvaParametriSetup(); }); } public async Task LoadSettingsAsync(string filePath, object settings) { - // Step 1: Load XML and read into DTO on background thread + // Step 1: Load XML into a temporary ParametriSetup so we don't mutate the injected + // user-preferences instance (singleton). var dto = await Task.Run(() => { - _parametriSetup.NomeFileSetup = filePath; - _parametriSetup.CaricaParametriSetup(); + var fileParams = new ParametriSetup(filePath); var loadedDto = new SettingsDto(); var properties = typeof(SettingsDto).GetProperties(BindingFlags.Public | BindingFlags.Instance); @@ -76,11 +77,11 @@ namespace ImageCatalog_2.Services object value; if (prop.PropertyType == typeof(string)) { - value = _parametriSetup.LeggiParametroString(xmlName); + value = fileParams.LeggiParametroString(xmlName); } else if (prop.PropertyType == typeof(bool)) { - value = _parametriSetup.LeggiParametroBoolean(xmlName); + value = fileParams.LeggiParametroBoolean(xmlName); } else if (prop.PropertyType == typeof(int)) {