Wire up the disposer for cleaning up unused objects, i.e disposing a VM will remove it from the view
This commit is contained in:
@@ -1,6 +0,0 @@
|
||||
namespace Hyperbar;
|
||||
|
||||
public interface IMapping<TFrom, TTo>
|
||||
{
|
||||
TTo Create();
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace Hyperbar;
|
||||
|
||||
public interface IViewModelFactory<TIn, TOut>
|
||||
{
|
||||
ValueTask<TOut> CreateAsync(TIn value);
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
namespace Hyperbar;
|
||||
|
||||
public interface IFactory<T>
|
||||
{
|
||||
T Create();
|
||||
}
|
||||
@@ -10,9 +10,6 @@ public class NotficationPipelineHandler<TFromNotification, ToNotification>(IMedi
|
||||
{
|
||||
private readonly IMediator mediator = mediator;
|
||||
|
||||
public ValueTask Handle(TFromNotification notification, CancellationToken cancellationToken)
|
||||
{
|
||||
return mediator.PublishAsync(new ToNotification(),
|
||||
cancellationToken);
|
||||
}
|
||||
public ValueTask Handle(TFromNotification notification, CancellationToken cancellationToken) =>
|
||||
mediator.PublishAsync(new ToNotification(), cancellationToken);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
namespace Hyperbar;
|
||||
|
||||
public record CollectionChanged<TValue> : INotification;
|
||||
@@ -1,5 +0,0 @@
|
||||
using System.Collections;
|
||||
|
||||
namespace Hyperbar;
|
||||
|
||||
public record ValueChanging<TValue> : INotification;
|
||||
@@ -0,0 +1,3 @@
|
||||
namespace Hyperbar;
|
||||
|
||||
public record Created<TValue>(TValue? Value = default) : INotification;
|
||||
@@ -8,4 +8,4 @@ public interface IObservableCollectionViewModel<TItem> :
|
||||
IList,
|
||||
IReadOnlyList<TItem>,
|
||||
INotifyCollectionChanged,
|
||||
INotificationHandler<ValueChanging<IEnumerable<TItem>>>;
|
||||
IInitializer;
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace Hyperbar;
|
||||
|
||||
public interface IViewModelEnumerator<TItem>
|
||||
{
|
||||
IAsyncEnumerable<TItem?> Next();
|
||||
}
|
||||
@@ -1,7 +1,10 @@
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using System.Collections;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Collections.Specialized;
|
||||
using System.Reactive.Disposables;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace Hyperbar;
|
||||
|
||||
@@ -11,14 +14,19 @@ public partial class ObservableCollectionViewModel<TItem> :
|
||||
{
|
||||
public ObservableCollection<TItem> collection = [];
|
||||
private readonly SynchronizationContext? context;
|
||||
private readonly IViewModelEnumerator<TItem>? enumerator;
|
||||
private readonly IServiceFactory serviceFactory;
|
||||
private readonly IDisposer disposer;
|
||||
|
||||
public ObservableCollectionViewModel(IServiceFactory serviceFactory,
|
||||
IMediator mediator)
|
||||
IMediator mediator,
|
||||
IDisposer disposer)
|
||||
{
|
||||
context = SynchronizationContext.Current;
|
||||
|
||||
this.serviceFactory = serviceFactory;
|
||||
this.disposer = disposer;
|
||||
|
||||
mediator.Subscribe(this);
|
||||
|
||||
collection.CollectionChanged += OnCollectionChanged;
|
||||
@@ -26,28 +34,44 @@ public partial class ObservableCollectionViewModel<TItem> :
|
||||
|
||||
public ObservableCollectionViewModel(IServiceFactory serviceFactory,
|
||||
IMediator mediator,
|
||||
IFactory<IEnumerable<TItem>> factory)
|
||||
IDisposer disposer,
|
||||
IViewModelEnumerator<TItem> enumerator)
|
||||
{
|
||||
context = SynchronizationContext.Current;
|
||||
|
||||
this.serviceFactory = serviceFactory;
|
||||
this.disposer = disposer;
|
||||
this.enumerator = enumerator;
|
||||
|
||||
mediator.Subscribe(this);
|
||||
|
||||
collection.CollectionChanged += OnCollectionChanged;
|
||||
|
||||
if (factory is not null && factory.Create() is { } items)
|
||||
|
||||
if (enumerator is not null)
|
||||
{
|
||||
AddRange(factory.Create());
|
||||
Task.Run(async () =>
|
||||
{
|
||||
await foreach (TItem? item in enumerator.Next())
|
||||
{
|
||||
if (item is not null)
|
||||
{
|
||||
Add(item);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public ObservableCollectionViewModel(IServiceFactory serviceFactory,
|
||||
IMediator mediator,
|
||||
IDisposer disposer,
|
||||
IEnumerable<TItem> items)
|
||||
{
|
||||
context = SynchronizationContext.Current;
|
||||
|
||||
this.serviceFactory = serviceFactory;
|
||||
this.disposer = disposer;
|
||||
|
||||
mediator.Subscribe(this);
|
||||
|
||||
collection.CollectionChanged += OnCollectionChanged;
|
||||
@@ -59,6 +83,10 @@ public partial class ObservableCollectionViewModel<TItem> :
|
||||
|
||||
public int Count => collection.Count;
|
||||
|
||||
public ICommand Initialize => new AsyncRelayCommand(InitializeAsync);
|
||||
|
||||
public bool Initialized { get; private set; }
|
||||
|
||||
bool IList.IsFixedSize => false;
|
||||
|
||||
bool ICollection<TItem>.IsReadOnly => false;
|
||||
@@ -157,6 +185,7 @@ public partial class ObservableCollectionViewModel<TItem> :
|
||||
context?.Post(state => Add(item), null);
|
||||
}
|
||||
}
|
||||
|
||||
public void Clear() => ClearItems();
|
||||
|
||||
public bool Contains(TItem item) => collection.Contains(item);
|
||||
@@ -171,19 +200,21 @@ public partial class ObservableCollectionViewModel<TItem> :
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable)collection).GetEnumerator();
|
||||
|
||||
//public ValueTask Handle(CollectionChanged<IEnumerable<TItem>> notification,
|
||||
// CancellationToken cancellationToken)
|
||||
//{
|
||||
// context?.Post(state => Clear(), null);
|
||||
// AddRange(notification.Items);
|
||||
|
||||
// return ValueTask.CompletedTask;
|
||||
//}
|
||||
|
||||
public int IndexOf(TItem item) => collection.IndexOf(item);
|
||||
|
||||
int IList.IndexOf(object? value) => IsCompatibleObject(value) ? IndexOf((TItem)value!) : -1;
|
||||
|
||||
public Task InitializeAsync()
|
||||
{
|
||||
if (Initialized)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
Initialized = true;
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public void Insert(int index, TItem item) => InsertItem(index, item);
|
||||
|
||||
void IList.Insert(int index, object? value)
|
||||
@@ -209,6 +240,7 @@ public partial class ObservableCollectionViewModel<TItem> :
|
||||
Remove((TItem)value!);
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveAt(int index) => RemoveItem(index);
|
||||
|
||||
protected virtual void ClearItems() => collection.Clear();
|
||||
@@ -217,7 +249,15 @@ public partial class ObservableCollectionViewModel<TItem> :
|
||||
{
|
||||
if (value is TItem item)
|
||||
{
|
||||
collection.Insert(index, item);
|
||||
disposer.Add(item, Disposable.Create(() =>
|
||||
{
|
||||
if (Contains(item))
|
||||
{
|
||||
Remove(item);
|
||||
}
|
||||
}));
|
||||
|
||||
context?.Post(state => collection.Insert(index, item), null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -230,13 +270,9 @@ public partial class ObservableCollectionViewModel<TItem> :
|
||||
|
||||
private void OnCollectionChanged(object? sender, NotifyCollectionChangedEventArgs args) =>
|
||||
CollectionChanged?.Invoke(this, args);
|
||||
|
||||
public ValueTask Handle(ValueChanging<IEnumerable<TItem>> notification,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public class ObservableCollectionViewModel(IServiceFactory serviceFactory, IMediator mediator) :
|
||||
ObservableCollectionViewModel<object>(serviceFactory, mediator);
|
||||
public class ObservableCollectionViewModel(IServiceFactory serviceFactory,
|
||||
IMediator mediator,
|
||||
IDisposer disposer) :
|
||||
ObservableCollectionViewModel<object>(serviceFactory, mediator, disposer);
|
||||
@@ -0,0 +1,3 @@
|
||||
namespace Hyperbar;
|
||||
|
||||
public record Removed<TValue>(TValue Value) : INotification;
|
||||
@@ -1,11 +1,11 @@
|
||||
|
||||
namespace Hyperbar;
|
||||
namespace Hyperbar;
|
||||
|
||||
public partial class WidgetBarViewModel(ITemplateFactory templateFactory,
|
||||
IServiceFactory serviceFactory,
|
||||
IMediator mediator,
|
||||
IDisposer disposer,
|
||||
IEnumerable<WidgetContainerViewModel> items) :
|
||||
ObservableCollectionViewModel<WidgetContainerViewModel>(serviceFactory, mediator, items),
|
||||
ObservableCollectionViewModel<WidgetContainerViewModel>(serviceFactory, mediator, disposer, items),
|
||||
ITemplatedViewModel
|
||||
{
|
||||
public ITemplateFactory TemplateFactory => templateFactory;
|
||||
|
||||
@@ -3,23 +3,20 @@ using CommunityToolkit.Mvvm.Input;
|
||||
|
||||
namespace Hyperbar;
|
||||
|
||||
public partial class WidgetButtonViewModel :
|
||||
WidgetComponentViewModel
|
||||
public partial class WidgetButtonViewModel(IServiceFactory serviceFactory,
|
||||
IMediator mediator,
|
||||
IDisposer disposer,
|
||||
ITemplateFactory templateFactory,
|
||||
Guid id = default,
|
||||
string? icon = null,
|
||||
RelayCommand? command = null) : WidgetComponentViewModel(serviceFactory, mediator, disposer, templateFactory)
|
||||
{
|
||||
[ObservableProperty]
|
||||
private string? icon;
|
||||
private Guid id = id;
|
||||
|
||||
[ObservableProperty]
|
||||
private IRelayCommand? click;
|
||||
private string? icon = icon;
|
||||
|
||||
public WidgetButtonViewModel(ITemplateFactory templateFactory,
|
||||
string? icon = null,
|
||||
Action? action = null) : base(templateFactory)
|
||||
{
|
||||
this.icon = icon;
|
||||
if (action is not null)
|
||||
{
|
||||
click = new RelayCommand(action);
|
||||
}
|
||||
}
|
||||
[ObservableProperty]
|
||||
private IRelayCommand? click = command;
|
||||
}
|
||||
@@ -2,8 +2,19 @@
|
||||
|
||||
namespace Hyperbar;
|
||||
|
||||
public partial class WidgetComponentViewModel(ITemplateFactory templateFactory) :
|
||||
public class ObservableViewModel(IServiceFactory serviceFactory,
|
||||
IMediator mediator,
|
||||
IDisposer disposer) :
|
||||
ObservableObject,
|
||||
IDisposable
|
||||
{
|
||||
public void Dispose() => disposer.Dispose(this);
|
||||
}
|
||||
|
||||
public partial class WidgetComponentViewModel(IServiceFactory serviceFactory,
|
||||
IMediator mediator,
|
||||
IDisposer disposer,
|
||||
ITemplateFactory templateFactory) : ObservableViewModel(serviceFactory, mediator, disposer),
|
||||
IWidgetComponentViewModel,
|
||||
ITemplatedViewModel
|
||||
{
|
||||
|
||||
@@ -6,9 +6,10 @@ namespace Hyperbar;
|
||||
public partial class WidgetContainerViewModel(ITemplateFactory templateFactory,
|
||||
IServiceFactory serviceFactory,
|
||||
IMediator mediator,
|
||||
IDisposer disposer,
|
||||
IEnumerable<IWidgetViewModel> items,
|
||||
bool alternate) :
|
||||
ObservableCollectionViewModel<IWidgetViewModel>(serviceFactory, mediator, items),
|
||||
ObservableCollectionViewModel<IWidgetViewModel>(serviceFactory, mediator, disposer, items),
|
||||
ITemplatedViewModel
|
||||
{
|
||||
[ObservableProperty]
|
||||
|
||||
Reference in New Issue
Block a user