Fixed disposer?
This commit is contained in:
@@ -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; }
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user