Fixed disposer?

This commit is contained in:
TheXamlGuy
2024-01-28 19:31:09 +00:00
parent 6d40220412
commit 3917639e8d
10 changed files with 79 additions and 88 deletions
@@ -4,7 +4,8 @@
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:interactions="using:Microsoft.Xaml.Interactions.Core" xmlns:interactions="using:Microsoft.Xaml.Interactions.Core"
xmlns:interactivity="using:Microsoft.Xaml.Interactivity"> xmlns:interactivity="using:Microsoft.Xaml.Interactivity"
Visibility="{x:Bind ViewModel.Visible, Mode=OneWay}">
<UserControl.Resources> <UserControl.Resources>
<SolidColorBrush x:Key="ButtonBackground" Color="Transparent" /> <SolidColorBrush x:Key="ButtonBackground" Color="Transparent" />
<SolidColorBrush x:Key="ButtonBorderBrush" Color="Transparent" /> <SolidColorBrush x:Key="ButtonBorderBrush" Color="Transparent" />
@@ -8,4 +8,6 @@ public sealed partial class MediaButtonView :
{ {
public MediaButtonView() => public MediaButtonView() =>
this.InitializeComponent(ref _contentLoaded); this.InitializeComponent(ref _contentLoaded);
private MediaButtonViewModel ViewModel => (MediaButtonViewModel)DataContext;
} }
@@ -2,14 +2,7 @@
namespace Hyperbar.Widget.MediaController.Windows; namespace Hyperbar.Widget.MediaController.Windows;
public class MediaButtonViewModel : public class MediaButtonViewModel(IServiceFactory serviceFactory,
WidgetButtonViewModel,
IInitialization,
INotificationHandler<Changed<PlaybackInformation>>
{
private readonly PlaybackButtonType buttonType;
public MediaButtonViewModel(IServiceFactory serviceFactory,
IMediator mediator, IMediator mediator,
IDisposer disposer, IDisposer disposer,
ITemplateFactory templateFactory, ITemplateFactory templateFactory,
@@ -17,12 +10,11 @@ public class MediaButtonViewModel :
Guid guid = default, Guid guid = default,
string? text = null, string? text = null,
string? icon = null, string? icon = null,
RelayCommand? command = null) : base (serviceFactory, mediator, disposer, templateFactory, guid, text, icon, command) RelayCommand? command = null) :
WidgetButtonViewModel(serviceFactory, mediator, disposer, templateFactory, guid, text, icon, command),
IInitialization,
INotificationHandler<Changed<PlaybackInformation>>
{ {
this.buttonType = buttonType;
mediator.Subscribe(this);
}
public Task Handle(Changed<PlaybackInformation> notification, public Task Handle(Changed<PlaybackInformation> notification,
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
@@ -31,10 +23,10 @@ public class MediaButtonViewModel :
switch (buttonType) switch (buttonType)
{ {
case PlaybackButtonType.Play: case PlaybackButtonType.Play:
Visible = information.Status is PlaybackStatus.Playing; Visible = information.Status is PlaybackStatus.Paused;
break; break;
case PlaybackButtonType.Pause: case PlaybackButtonType.Pause:
Visible = information.Status is PlaybackStatus.Paused; Visible = information.Status is PlaybackStatus.Playing;
break; break;
} }
} }
@@ -5,28 +5,31 @@ namespace Hyperbar.Widget.MediaController.Windows;
public class MediaControllerHandler(IMediator mediator, public class MediaControllerHandler(IMediator mediator,
IServiceScopeProvider<MediaController> scopeProvider, IServiceScopeProvider<MediaController> scopeProvider,
ICache<MediaController, MediaControllerViewModel> cache) : ICache<MediaController, MediaControllerViewModel> cache) :
INotificationHandler<Created<MediaController>> INotificationHandler<Created<MediaController>>,
INotificationHandler<Removed<MediaController>>
{ {
public async Task Handle(Created<MediaController> notification, public async Task Handle(Created<MediaController> notification,
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
if (notification.Value is MediaController mediaController) if (notification.Value is MediaController mediaController &&
scopeProvider.TryGet(mediaController, out IServiceScope? serviceScope) &&
serviceScope?.ServiceProvider.GetService<IFactory<MediaController, MediaControllerViewModel?>>()
is IFactory<MediaController, MediaControllerViewModel?> factory &&
factory.Create(mediaController) is MediaControllerViewModel viewModel)
{ {
if (scopeProvider.TryGet(mediaController, out IServiceScope? serviceScope)) cache.Add(mediaController, viewModel);
await mediator.PublishAsync(new Created<MediaControllerViewModel>(viewModel), cancellationToken);
}
}
if (serviceScope is not null) public async Task Handle(Removed<MediaController> notification, CancellationToken cancellationToken)
{ {
if (serviceScope.ServiceProvider.GetService<IFactory<MediaController, MediaControllerViewModel?>>() if (notification.Value is MediaController mediaController &&
is IFactory<MediaController, MediaControllerViewModel?> factory) cache.TryGetValue(mediaController, out MediaControllerViewModel? viewModel) &&
viewModel is not null)
{ {
if (factory.Create(mediaController) is MediaControllerViewModel mediaControllerViewModel) await mediator.PublishAsync(new Removed<MediaControllerViewModel>(viewModel), cancellationToken);
{ cache.Remove(mediaController);
cache.Add(mediaController, mediaControllerViewModel);
await mediator.PublishAsync(new Created<MediaControllerViewModel>(mediaControllerViewModel),
cancellationToken);
}
}
}
} }
} }
} }
@@ -48,7 +48,7 @@ public class MediaControllerManager(IMediator mediator,
{ {
if (!sessions.Any(x => x.SourceAppUserModelId == session.Key.SourceAppUserModelId)) if (!sessions.Any(x => x.SourceAppUserModelId == session.Key.SourceAppUserModelId))
{ {
await dispatcher.InvokeAsync(() => disposer.Dispose(session.Value)); await mediator.PublishAsync(new Removed<MediaController>(session.Value));
cache.Remove(session); cache.Remove(session);
} }
} }
@@ -30,8 +30,6 @@ public class MediaControllerViewModel :
Add<MediaButtonViewModel>(PlaybackButtonType.Forward, Add<MediaButtonViewModel>(PlaybackButtonType.Forward,
"Forward", "\uEB9D", "Forward", "\uEB9D",
new RelayCommand(async () => await mediator.PublishAsync<Forward>())); new RelayCommand(async () => await mediator.PublishAsync<Forward>()));
mediator.Subscribe(this);
} }
public ITemplateFactory TemplateFactory { get; set; } public ITemplateFactory TemplateFactory { get; set; }
-10
View File
@@ -41,16 +41,6 @@ public class Cache<TKey, TValue>(IDisposer disposer) :
TValue value) TValue value)
{ {
cache.TryAdd(key, value); cache.TryAdd(key, value);
disposer.Add(value, Disposable.Create(() =>
{
Remove(key);
}));
disposer.Add(key, Disposable.Create(() =>
{
Remove(key);
}));
} }
public void Clear() => cache.Clear(); public void Clear() => cache.Clear();
@@ -1,10 +1,3 @@
using System.Collections; namespace Hyperbar;
using System.Collections.Specialized;
namespace Hyperbar; public interface IObservableCollectionViewModel<TItem>;
public interface IObservableCollectionViewModel<TItem> :
IList<TItem>,
IList,
IReadOnlyList<TItem>,
INotifyCollectionChanged;
@@ -11,6 +11,10 @@ namespace Hyperbar;
public partial class ObservableCollectionViewModel<TItem> : public partial class ObservableCollectionViewModel<TItem> :
ObservableObject, ObservableObject,
IObservableCollectionViewModel<TItem>, IObservableCollectionViewModel<TItem>,
IList<TItem>,
IList,
IReadOnlyList<TItem>,
INotifyCollectionChanged,
INotificationHandler<Removed<TItem>>, INotificationHandler<Removed<TItem>>,
INotificationHandler<Created<TItem>>, INotificationHandler<Created<TItem>>,
INotificationHandler<Inserted<TItem>>, INotificationHandler<Inserted<TItem>>,
@@ -134,6 +138,12 @@ public partial class ObservableCollectionViewModel<TItem> :
InsertItem(index, item); InsertItem(index, item);
} }
public void Add(object item)
{
int index = collection.Count;
InsertItem(index, (TItem)item);
}
int IList.Add(object? value) int IList.Add(object? value)
{ {
TItem? item = default; TItem? item = default;
@@ -159,7 +169,15 @@ public partial class ObservableCollectionViewModel<TItem> :
} }
} }
public void Clear() => ClearItems(); public void Clear()
{
foreach (TItem item in collection)
{
Disposer.Dispose(item);
}
ClearItems();
}
public bool Contains(TItem item) => public bool Contains(TItem item) =>
collection.Contains(item); collection.Contains(item);
@@ -173,8 +191,11 @@ public partial class ObservableCollectionViewModel<TItem> :
void ICollection.CopyTo(Array array, int index) => void ICollection.CopyTo(Array array, int index) =>
collection.CopyTo((TItem[])array, index); collection.CopyTo((TItem[])array, index);
public void Dispose() => public virtual void Dispose()
{
GC.SuppressFinalize(this);
Disposer.Dispose(this); Disposer.Dispose(this);
}
public System.Collections.Generic.IEnumerator<TItem> GetEnumerator() => public System.Collections.Generic.IEnumerator<TItem> GetEnumerator() =>
collection.GetEnumerator(); collection.GetEnumerator();
@@ -187,15 +208,9 @@ public partial class ObservableCollectionViewModel<TItem> :
{ {
foreach (TItem item in this.ToList()) foreach (TItem item in this.ToList())
{ {
if (notification.Value is not null) if (notification.Value is not null && notification.Value.Equals(item))
{ {
if (notification.Value.Equals(item)) Remove(item);
{
if (item is IDisposable disposable)
{
disposable.Dispose();
}
}
} }
} }
@@ -279,7 +294,7 @@ public partial class ObservableCollectionViewModel<TItem> :
return false; return false;
} }
Disposer.Remove(this, item); Disposer.Dispose(item);
RemoveItem(index); RemoveItem(index);
return true; return true;
@@ -302,14 +317,13 @@ public partial class ObservableCollectionViewModel<TItem> :
protected virtual void InsertItem(int index, protected virtual void InsertItem(int index,
TItem value) TItem value)
{ {
Disposer.Add(this, Disposable.Create(() => Disposer.Add(this, value);
Disposer.Add(value, value, Disposable.Create(() =>
{ {
Remove(value); if (value is IList collection)
}));
Disposer.Add(value, Disposable.Create(() =>
{ {
Remove(value); collection.Clear();
}
})); }));
collection.Insert(index, value); collection.Insert(index, value);
+9 -11
View File
@@ -8,7 +8,7 @@ public class Mediator(IServiceProvider provider,
IDispatcher dispatcher) : IDispatcher dispatcher) :
IMediator IMediator
{ {
private readonly ConcurrentDictionary<object, List<dynamic>> subjects = []; private readonly ConcurrentDictionary<object, List<dynamic>> subscriptions = [];
public Task PublishAsync<TNotification>(object key, public Task PublishAsync<TNotification>(object key,
CancellationToken cancellationToken = default) CancellationToken cancellationToken = default)
@@ -46,11 +46,14 @@ public class Mediator(IServiceProvider provider,
List<INotificationHandler<TNotification>> handlers = List<INotificationHandler<TNotification>> handlers =
provider.GetServices<INotificationHandler<TNotification>>().ToList(); provider.GetServices<INotificationHandler<TNotification>>().ToList();
foreach (KeyValuePair<object, List<dynamic>> handler in subjects) foreach (KeyValuePair<object, List<dynamic>> subscriber in subscriptions)
{ {
if (key is not null && handler.Key.Equals(key) || handler.Key.Equals(typeof(TNotification))) if (subscriber.Key.Equals($"{(key is not null ? $"{key}:" : "")}{typeof(TNotification)}"))
{ {
handlers.Add(handler.Value[0]); foreach (dynamic handler in subscriber.Value)
{
handlers.Add(handler);
}
} }
} }
@@ -111,14 +114,9 @@ public class Mediator(IServiceProvider provider,
foreach (Type interfaceType in GetNotificationHandlerInterfaces(handlerType)) foreach (Type interfaceType in GetNotificationHandlerInterfaces(handlerType))
{ {
if (interfaceType.GetGenericArguments().FirstOrDefault() if (interfaceType.GetGenericArguments().FirstOrDefault() is Type argumentType)
is Type argumentType)
{ {
if (object.Equals(key, default)) subscriptions.AddOrUpdate($"{(key is not null ? $"{key}:" : "")}{argumentType}", new List<object> { handler }, (value, collection) =>
{
}
subjects.AddOrUpdate(key ?? argumentType, new List<object> { handler }, (value, collection) =>
{ {
collection.Add(handler); collection.Add(handler);
return collection; return collection;