diff --git a/StabilityMatrix.Avalonia/ViewModels/LoadableViewModelBase.cs b/StabilityMatrix.Avalonia/ViewModels/LoadableViewModelBase.cs index 81fc5d1a..476a6496 100644 --- a/StabilityMatrix.Avalonia/ViewModels/LoadableViewModelBase.cs +++ b/StabilityMatrix.Avalonia/ViewModels/LoadableViewModelBase.cs @@ -27,11 +27,16 @@ public abstract class LoadableViewModelBase : ViewModelBase, IJsonLoadableState { nameof(HasErrors), }; + + protected static readonly JsonSerializerOptions SerializerOptions = new() + { + IgnoreReadOnlyProperties = true, + }; private static bool ShouldIgnoreProperty(PropertyInfo property) { - // Check not read-only - if (property.SetMethod is null) + // Skip if read-only and not IJsonLoadableState + if (property.SetMethod is null && !typeof(IJsonLoadableState).IsAssignableFrom(property.PropertyType)) { Logger.Trace("Skipping {Property} - read-only", property.Name); return true; @@ -123,7 +128,7 @@ public abstract class LoadableViewModelBase : ViewModelBase, IJsonLoadableState { Logger.Trace("Loading {Property} ({Type})", property.Name, property.PropertyType); - var propertyValue = value.Deserialize(property.PropertyType); + var propertyValue = value.Deserialize(property.PropertyType, SerializerOptions); property.SetValue(this, propertyValue); } } @@ -176,7 +181,7 @@ public abstract class LoadableViewModelBase : ViewModelBase, IJsonLoadableState var value = property.GetValue(this); if (value is not null) { - state.Add(property.Name, JsonSerializer.SerializeToNode(value)); + state.Add(property.Name, JsonSerializer.SerializeToNode(value, SerializerOptions)); } } } diff --git a/StabilityMatrix.Tests/Avalonia/LoadableViewModelBaseTests.cs b/StabilityMatrix.Tests/Avalonia/LoadableViewModelBaseTests.cs index 83df2b4c..5448fa27 100644 --- a/StabilityMatrix.Tests/Avalonia/LoadableViewModelBaseTests.cs +++ b/StabilityMatrix.Tests/Avalonia/LoadableViewModelBaseTests.cs @@ -24,13 +24,18 @@ public class TestLoadableViewModel : LoadableViewModelBase public class TestLoadableViewModelReadOnly : LoadableViewModelBase { public int ReadOnly { get; } - + public TestLoadableViewModelReadOnly(int readOnly) { ReadOnly = readOnly; } } +public class TestLoadableViewModelReadOnlyLoadable : LoadableViewModelBase +{ + public TestLoadableViewModel ReadOnlyLoadable { get; } = new(); +} + public partial class TestLoadableViewModelObservable : LoadableViewModelBase { [ObservableProperty] @@ -228,4 +233,22 @@ public class LoadableViewModelBaseTests // Read only property should have been ignored Assert.AreEqual(123, vm2.ReadOnly); } + + [TestMethod] + public void TestLoadStateFromJsonObject_ReadOnlyLoadable() + { + var vm = new TestLoadableViewModelReadOnlyLoadable + { + ReadOnlyLoadable = + { + Included = "abc-123" + } + }; + + var state = vm.SaveStateToJsonObject(); + + // Check readonly loadable property was serialized + Assert.AreEqual(1, state.Count); + Assert.AreEqual("abc-123", state["ReadOnlyLoadable"].Deserialize()!.Included); + } }