Replaced multiple mutually-exclusive boolean properties for thumbnail text options with a single enum (`ThumbnailOption`) in the data model. Updated WinForms UI to use a ComboBox instead of radio buttons for selecting thumbnail mode. Adjusted designer, mapping profile, settings DTO, and settings service for enum support and backward compatibility. Simplified thumbnail generation logic and improved maintainability by ensuring only one mode can be selected at a time.
198 lines
7.9 KiB
C#
198 lines
7.9 KiB
C#
using System;
|
|
using System.Reflection;
|
|
using System.Threading.Tasks;
|
|
using System.Xml.Serialization;
|
|
using ImageCatalog;
|
|
using ImageCatalog_2.Models;
|
|
using Microsoft.Extensions.Logging;
|
|
|
|
namespace ImageCatalog_2.Services
|
|
{
|
|
/// <summary>
|
|
/// Modern settings service that uses DTO with attributes for serialization
|
|
/// </summary>
|
|
public class SettingsService : ISettingsService
|
|
{
|
|
private readonly ParametriSetup _parametriSetup;
|
|
private readonly ILogger<SettingsService> _logger;
|
|
|
|
public SettingsService(ParametriSetup parametriSetup, ILogger<SettingsService> logger)
|
|
{
|
|
_parametriSetup = parametriSetup;
|
|
_logger = logger;
|
|
}
|
|
|
|
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(() =>
|
|
{
|
|
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)
|
|
{
|
|
var xmlAttr = prop.GetCustomAttribute<XmlElementAttribute>();
|
|
if (xmlAttr == null)
|
|
continue;
|
|
|
|
var xmlName = xmlAttr.ElementName;
|
|
var value = prop.GetValue(dto);
|
|
|
|
fileParams.AggiornaParametro(xmlName, value);
|
|
}
|
|
|
|
fileParams.SalvaParametriSetup();
|
|
});
|
|
}
|
|
|
|
public async Task LoadSettingsAsync(string filePath, object settings)
|
|
{
|
|
// Step 1: Load XML into a temporary ParametriSetup so we don't mutate the injected
|
|
// user-preferences instance (singleton).
|
|
var dto = await Task.Run(() =>
|
|
{
|
|
var fileParams = new ParametriSetup(filePath);
|
|
|
|
var loadedDto = new SettingsDto();
|
|
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<XmlElementAttribute>();
|
|
if (xmlAttr == null)
|
|
continue; // Skip properties without XmlElement attribute
|
|
|
|
var xmlName = xmlAttr.ElementName;
|
|
|
|
try
|
|
{
|
|
object value;
|
|
if (prop.PropertyType == typeof(string))
|
|
{
|
|
value = fileParams.LeggiParametroString(xmlName);
|
|
}
|
|
else if (prop.PropertyType == typeof(bool))
|
|
{
|
|
value = fileParams.LeggiParametroBoolean(xmlName);
|
|
}
|
|
else if (prop.PropertyType.IsEnum)
|
|
{
|
|
// Read enum as string from XML and try to parse to the enum type. Fall back to default.
|
|
var str = fileParams.LeggiParametroString(xmlName);
|
|
try
|
|
{
|
|
var enumValue = Enum.Parse(prop.PropertyType, str ?? string.Empty, true);
|
|
value = enumValue;
|
|
}
|
|
catch
|
|
{
|
|
// try numeric
|
|
var intVal = fileParams.LeggiParametro<int>(xmlName, (int)(prop.GetValue(loadedDto) ?? 0));
|
|
value = Enum.ToObject(prop.PropertyType, intVal);
|
|
}
|
|
}
|
|
else if (prop.PropertyType == typeof(int))
|
|
{
|
|
value = fileParams.LeggiParametro<int>(xmlName, (int)(prop.GetValue(loadedDto) ?? 0));
|
|
}
|
|
else if (prop.PropertyType == typeof(double))
|
|
{
|
|
value = fileParams.LeggiParametro<double>(xmlName, (double)(prop.GetValue(loadedDto) ?? 0.0));
|
|
}
|
|
else if (prop.PropertyType == typeof(DateTime))
|
|
{
|
|
var strValue = fileParams.LeggiParametroString(xmlName);
|
|
if (DateTime.TryParse(strValue, out var dateValue))
|
|
{
|
|
value = dateValue;
|
|
}
|
|
else
|
|
{
|
|
value = (DateTime)(prop.GetValue(loadedDto) ?? DateTime.Now);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
continue;
|
|
}
|
|
|
|
prop.SetValue(loadedDto, value);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Failed to read property {XmlName} -> {PropertyName}", xmlName, prop.Name);
|
|
}
|
|
}
|
|
|
|
return loadedDto;
|
|
// End of LoadSettingsAsync method
|
|
});
|
|
|
|
// Step 2: Apply DTO values to ViewModel on UI thread
|
|
DtoToViewModel(dto, settings);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Converts DataModel (ViewModel) to SettingsDto
|
|
/// </summary>
|
|
private SettingsDto ViewModelToDto(object viewModel)
|
|
{
|
|
var vmType = viewModel.GetType();
|
|
var dto = new SettingsDto();
|
|
var dtoProps = typeof(SettingsDto).GetProperties(BindingFlags.Public | BindingFlags.Instance);
|
|
|
|
foreach (var dtoProp in dtoProps)
|
|
{
|
|
// Find matching property in ViewModel by name
|
|
var vmProp = vmType.GetProperty(dtoProp.Name, BindingFlags.Public | BindingFlags.Instance);
|
|
if (vmProp != null && vmProp.CanRead)
|
|
{
|
|
var value = vmProp.GetValue(viewModel);
|
|
dtoProp.SetValue(dto, value);
|
|
}
|
|
}
|
|
|
|
return dto;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Copies values from SettingsDto to DataModel (ViewModel)
|
|
/// </summary>
|
|
private void DtoToViewModel(SettingsDto dto, object viewModel)
|
|
{
|
|
var vmType = viewModel.GetType();
|
|
var dtoProps = typeof(SettingsDto).GetProperties(BindingFlags.Public | BindingFlags.Instance);
|
|
|
|
foreach (var dtoProp in dtoProps)
|
|
{
|
|
// Find matching property in ViewModel by name
|
|
var vmProp = vmType.GetProperty(dtoProp.Name, BindingFlags.Public | BindingFlags.Instance);
|
|
if (vmProp != null && vmProp.CanWrite)
|
|
{
|
|
var value = dtoProp.GetValue(dto);
|
|
|
|
// Don't update if empty string and current value is not empty
|
|
if (dtoProp.PropertyType == typeof(string) && string.IsNullOrEmpty((string)value))
|
|
{
|
|
var currentValue = vmProp.GetValue(viewModel) as string;
|
|
if (!string.IsNullOrEmpty(currentValue))
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
vmProp.SetValue(viewModel, value);
|
|
_logger.LogDebug("Set {PropertyName} = {Value}", vmProp.Name, value);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|