From e783dcaa58aa5f659068bd309785848c0b5fb0e5 Mon Sep 17 00:00:00 2001 From: Robert Date: Fri, 12 May 2023 23:27:27 +0200 Subject: [PATCH] Fixed VM disposal issues --- .../Providers/Input/LinuxInputDeviceFinder.cs | 5 ++-- .../PropertyInput/PropertyInputService.cs | 2 +- .../PropertyInput/PropertyInputViewModel.cs | 26 ++----------------- src/Artemis.UI/DryIoc/ContainerExtensions.cs | 2 +- src/Artemis.UI/Screens/Home/HomeView.axaml | 3 ++- .../Properties/Tree/TreePropertyView.axaml.cs | 10 ++++--- .../Properties/Tree/TreePropertyViewModel.cs | 1 - .../ProfileEditor/ProfileEditorViewModel.cs | 4 +-- 8 files changed, 17 insertions(+), 36 deletions(-) diff --git a/src/Artemis.UI.Linux/Providers/Input/LinuxInputDeviceFinder.cs b/src/Artemis.UI.Linux/Providers/Input/LinuxInputDeviceFinder.cs index e8e6dfbc5..778ff432e 100644 --- a/src/Artemis.UI.Linux/Providers/Input/LinuxInputDeviceFinder.cs +++ b/src/Artemis.UI.Linux/Providers/Input/LinuxInputDeviceFinder.cs @@ -11,10 +11,9 @@ public static class LinuxInputDeviceFinder public static IEnumerable Find() { - var lineGroups = File.ReadAllLines(DEVICES_FILE) - .PartitionBy(s => s?.Length == 0); //split on empty lines + IEnumerable> lineGroups = File.ReadAllLines(DEVICES_FILE).PartitionBy(s => s?.Length == 0); //split on empty lines - foreach (var lineGroup in lineGroups) + foreach (IEnumerable lineGroup in lineGroups) { LinuxInputDevice device; diff --git a/src/Artemis.UI.Shared/Services/PropertyInput/PropertyInputService.cs b/src/Artemis.UI.Shared/Services/PropertyInput/PropertyInputService.cs index 6f91fbdfe..9ed8048c1 100644 --- a/src/Artemis.UI.Shared/Services/PropertyInput/PropertyInputService.cs +++ b/src/Artemis.UI.Shared/Services/PropertyInput/PropertyInputService.cs @@ -54,7 +54,7 @@ internal class PropertyInputService : IPropertyInputService return existing; } - _container.Register(viewModelType); + _container.Register(viewModelType, setup: Setup.With(preventDisposal: true)); PropertyInputRegistration registration = new(this, plugin, supportedType, viewModelType); _registeredPropertyEditors.Add(registration); return registration; diff --git a/src/Artemis.UI.Shared/Services/PropertyInput/PropertyInputViewModel.cs b/src/Artemis.UI.Shared/Services/PropertyInput/PropertyInputViewModel.cs index d08f340de..1382de03b 100644 --- a/src/Artemis.UI.Shared/Services/PropertyInput/PropertyInputViewModel.cs +++ b/src/Artemis.UI.Shared/Services/PropertyInput/PropertyInputViewModel.cs @@ -220,7 +220,7 @@ public abstract class PropertyInputViewModel : PropertyInputViewModel /// /// For internal use only, implement instead. /// -public abstract class PropertyInputViewModel : ReactiveValidationObject, IActivatableViewModel, IDisposable +public abstract class PropertyInputViewModel : ReactiveValidationObject, IActivatableViewModel { /// /// Prevents this type being implemented directly, implement @@ -228,29 +228,7 @@ public abstract class PropertyInputViewModel : ReactiveValidationObject, IActiva /// // ReSharper disable once UnusedMember.Global internal abstract object InternalGuard { get; } - - /// - /// Releases the unmanaged resources used by the object and optionally releases the managed resources. - /// - /// - /// to release both managed and unmanaged resources; - /// to release only unmanaged resources. - /// - protected virtual void Dispose(bool disposing) - { - } - - #region Implementation of IActivatableViewModel - + /// public ViewModelActivator Activator { get; } = new(); - - #endregion - - /// - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } } \ No newline at end of file diff --git a/src/Artemis.UI/DryIoc/ContainerExtensions.cs b/src/Artemis.UI/DryIoc/ContainerExtensions.cs index 310b06b21..da3e9a188 100644 --- a/src/Artemis.UI/DryIoc/ContainerExtensions.cs +++ b/src/Artemis.UI/DryIoc/ContainerExtensions.cs @@ -25,7 +25,7 @@ public static class ContainerExtensions Assembly[] thisAssembly = {typeof(ContainerExtensions).Assembly}; container.RegisterMany(thisAssembly, type => type.IsAssignableTo(), setup: Setup.With(preventDisposal: true)); - container.RegisterMany(thisAssembly, type => type.IsAssignableTo() && type.IsInterface); + container.RegisterMany(thisAssembly, type => type.IsAssignableTo() && type.IsInterface, setup: Setup.With(preventDisposal: true)); container.RegisterMany(thisAssembly, type => type.IsAssignableTo() && type != typeof(PropertyVmFactory)); container.Register(Reuse.Singleton); diff --git a/src/Artemis.UI/Screens/Home/HomeView.axaml b/src/Artemis.UI/Screens/Home/HomeView.axaml index d6b0bbe35..2ce2016a0 100644 --- a/src/Artemis.UI/Screens/Home/HomeView.axaml +++ b/src/Artemis.UI/Screens/Home/HomeView.axaml @@ -13,7 +13,8 @@ VerticalAlignment="Top" Source="/Assets/Images/home-banner.png" Height="200" - Stretch="UniformToFill" /> + Stretch="UniformToFill" + RenderOptions.BitmapInterpolationMode="HighQuality"/> { - Observable.FromEventPattern(e => ViewModel!.BaseLayerProperty.CurrentValueSet += e, e => ViewModel!.BaseLayerProperty.CurrentValueSet -= e) - .Subscribe(_ => this.BringIntoView()) - .DisposeWith(d); + ITreePropertyViewModel? viewModel = ViewModel; + if (viewModel != null) + { + Observable.FromEventPattern(e => viewModel.BaseLayerProperty.CurrentValueSet += e, e => viewModel.BaseLayerProperty.CurrentValueSet -= e) + .Subscribe(_ => this.BringIntoView()) + .DisposeWith(d); + } }); } diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Tree/TreePropertyViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Tree/TreePropertyViewModel.cs index ecceb942b..8c7e214a5 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Tree/TreePropertyViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Tree/TreePropertyViewModel.cs @@ -32,7 +32,6 @@ internal class TreePropertyViewModel : ActivatableViewModelBase, ITreePropert _profileEditorService.Time.Subscribe(t => _time = t).DisposeWith(d); _isCurrentlySelected = _profileEditorService.LayerProperty.Select(l => l == LayerProperty).ToProperty(this, vm => vm.IsCurrentlySelected).DisposeWith(d); _dataBindingEnabled = LayerProperty.BaseDataBinding.AsObservable().Select(b => b.IsEnabled).ToProperty(this, vm => vm.DataBindingEnabled).DisposeWith(d); - this.WhenAnyValue(vm => vm.LayerProperty.KeyframesEnabled).Subscribe(_ => this.RaisePropertyChanged(nameof(KeyframesEnabled))).DisposeWith(d); }); diff --git a/src/Artemis.UI/Screens/ProfileEditor/ProfileEditorViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/ProfileEditorViewModel.cs index 435ab4655..7351e4f80 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/ProfileEditorViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/ProfileEditorViewModel.cs @@ -22,7 +22,6 @@ namespace Artemis.UI.Screens.ProfileEditor; public class ProfileEditorViewModel : MainScreenViewModel { - private readonly IMainWindowService _mainWindowService; private readonly IProfileEditorService _profileEditorService; private readonly ISettingsService _settingsService; private readonly SourceList _tools; @@ -51,7 +50,6 @@ public class ProfileEditorViewModel : MainScreenViewModel { _profileEditorService = profileEditorService; _settingsService = settingsService; - _mainWindowService = mainWindowService; _tools = new SourceList(); _tools.AddRange(toolViewModels); @@ -77,6 +75,8 @@ public class ProfileEditorViewModel : MainScreenViewModel { mainWindowService.MainWindowFocused -= MainWindowServiceOnMainWindowFocused; mainWindowService.MainWindowUnfocused -= MainWindowServiceOnMainWindowUnfocused; + foreach (IToolViewModel toolViewModel in _tools.Items) + toolViewModel.Dispose(); }).DisposeWith(d); // Slow and steady wins the race (and doesn't lock up the entire UI)