Fixes to settings
This commit is contained in:
parent
d73389d791
commit
fc7175c2f7
6 changed files with 628 additions and 267 deletions
|
|
@ -1,22 +1,25 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
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 reflection to automatically save/load all properties
|
||||
/// 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)
|
||||
public SettingsService(ParametriSetup parametriSetup, ILogger<SettingsService> logger)
|
||||
{
|
||||
_parametriSetup = parametriSetup;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public Task SaveSettingsAsync(string filePath, object settings)
|
||||
|
|
@ -25,85 +28,153 @@ namespace ImageCatalog_2.Services
|
|||
{
|
||||
_parametriSetup.NomeFileSetup = filePath;
|
||||
|
||||
// Use reflection to get all properties and save them
|
||||
var properties = settings.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance)
|
||||
.Where(p => p.CanRead && IsSerializableType(p.PropertyType));
|
||||
// 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 value = prop.GetValue(settings);
|
||||
_parametriSetup.AggiornaParametro(prop.Name, value);
|
||||
// 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;
|
||||
var value = prop.GetValue(dto);
|
||||
|
||||
_parametriSetup.AggiornaParametro(xmlName, value);
|
||||
}
|
||||
|
||||
_parametriSetup.SalvaParametriSetup();
|
||||
});
|
||||
}
|
||||
|
||||
public Task LoadSettingsAsync(string filePath, object settings)
|
||||
public async Task LoadSettingsAsync(string filePath, object settings)
|
||||
{
|
||||
return Task.Run(() =>
|
||||
// Step 1: Load XML and read into DTO on background thread
|
||||
var dto = await Task.Run(() =>
|
||||
{
|
||||
_parametriSetup.NomeFileSetup = filePath;
|
||||
_parametriSetup.CaricaParametriSetup();
|
||||
|
||||
// Use reflection to get all properties and load them
|
||||
var properties = settings.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance)
|
||||
.Where(p => p.CanWrite && IsSerializableType(p.PropertyType));
|
||||
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 = _parametriSetup.LeggiParametroString(prop.Name);
|
||||
// Don't update if empty string and current value is not empty
|
||||
if (string.IsNullOrEmpty((string)value))
|
||||
{
|
||||
var currentValue = prop.GetValue(settings) as string;
|
||||
if (!string.IsNullOrEmpty(currentValue))
|
||||
{
|
||||
continue; // Skip if no value in settings but there's a default
|
||||
}
|
||||
}
|
||||
value = _parametriSetup.LeggiParametroString(xmlName);
|
||||
}
|
||||
else if (prop.PropertyType == typeof(bool))
|
||||
{
|
||||
value = _parametriSetup.LeggiParametroBoolean(prop.Name);
|
||||
value = _parametriSetup.LeggiParametroBoolean(xmlName);
|
||||
}
|
||||
else if (prop.PropertyType == typeof(int))
|
||||
{
|
||||
value = _parametriSetup.LeggiParametro<int>(prop.Name, (int)(prop.GetValue(settings) ?? 0));
|
||||
value = _parametriSetup.LeggiParametro<int>(xmlName, (int)(prop.GetValue(loadedDto) ?? 0));
|
||||
}
|
||||
else if (prop.PropertyType == typeof(double))
|
||||
{
|
||||
value = _parametriSetup.LeggiParametro<double>(prop.Name, (double)(prop.GetValue(settings) ?? 0.0));
|
||||
value = _parametriSetup.LeggiParametro<double>(xmlName, (double)(prop.GetValue(loadedDto) ?? 0.0));
|
||||
}
|
||||
else if (prop.PropertyType == typeof(DateTime))
|
||||
{
|
||||
var strValue = _parametriSetup.LeggiParametroString(xmlName);
|
||||
if (DateTime.TryParse(strValue, out var dateValue))
|
||||
{
|
||||
value = dateValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
value = (DateTime)(prop.GetValue(loadedDto) ?? DateTime.Now);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
continue; // Skip unsupported types
|
||||
continue;
|
||||
}
|
||||
|
||||
prop.SetValue(settings, value);
|
||||
prop.SetValue(loadedDto, value);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Skip properties that can't be loaded
|
||||
System.Diagnostics.Debug.WriteLine($"Failed to load property {prop.Name}: {ex.Message}");
|
||||
_logger.LogError(ex, "Failed to read property {XmlName} -> {PropertyName}", xmlName, prop.Name);
|
||||
}
|
||||
}
|
||||
|
||||
return loadedDto;
|
||||
});
|
||||
|
||||
// Step 2: Apply DTO values to ViewModel on UI thread
|
||||
DtoToViewModel(dto, settings);
|
||||
}
|
||||
|
||||
private bool IsSerializableType(Type type)
|
||||
/// <summary>
|
||||
/// Converts DataModel (ViewModel) to SettingsDto
|
||||
/// </summary>
|
||||
private SettingsDto ViewModelToDto(object viewModel)
|
||||
{
|
||||
return type == typeof(string) ||
|
||||
type == typeof(int) ||
|
||||
type == typeof(bool) ||
|
||||
type == typeof(double) ||
|
||||
type == typeof(float) ||
|
||||
type == typeof(decimal);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue