This commit is contained in:
TheXamlGuy
2024-02-10 20:19:01 +00:00
parent ecfac99868
commit 565c6866d8
60 changed files with 445 additions and 381 deletions
+1 -1
View File
@@ -24,7 +24,7 @@ public sealed class NavigateAction :
{ {
if (frameworkElement.DataContext is IObservableViewModel observableViewModel) if (frameworkElement.DataContext is IObservableViewModel observableViewModel)
{ {
observableViewModel.Mediator.PublishAsync(new Navigate(Path)) observableViewModel.Publisher.PublishAsync(new Navigate(Path))
.GetAwaiter().GetResult(); .GetAwaiter().GetResult();
} }
} }
+10 -1
View File
@@ -4,6 +4,15 @@ using Microsoft.UI.Xaml.Markup;
namespace Hyperbar.UI.Windows; namespace Hyperbar.UI.Windows;
public class ViewModelBinder
{
public void Bind(object viewModel,
FrameworkElement view)
{
view.DataContext ??= viewModel;
}
}
public class ViewModelTemplate(IViewModelTemplateDescriptorProvider descriptors) : public class ViewModelTemplate(IViewModelTemplateDescriptorProvider descriptors) :
DataTemplateSelector, DataTemplateSelector,
IViewModelTemplate IViewModelTemplate
@@ -19,7 +28,7 @@ public class ViewModelTemplate(IViewModelTemplateDescriptorProvider descriptors)
DependencyObject container) => DependencyObject container) =>
SelectTemplateCore(item); SelectTemplateCore(item);
private DataTemplate CreateDataTemplate(IViewModelTemplateDescriptor descriptor) private static DataTemplate CreateDataTemplate(IViewModelTemplateDescriptor descriptor)
{ {
string xamlString = @$" string xamlString = @$"
<DataTemplate xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation"" <DataTemplate xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation""
-6
View File
@@ -1,17 +1,11 @@
using Hyperbar.Interop.Windows; using Hyperbar.Interop.Windows;
using Microsoft.UI.Windowing; using Microsoft.UI.Windowing;
using Microsoft.UI.Xaml; using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Windows.Graphics; using Windows.Graphics;
using WinRT.Interop; using WinRT.Interop;
namespace Hyperbar.UI.Windows; namespace Hyperbar.UI.Windows;
public class NavigationItemTemplateSelector :
DataTemplateSelector
{
}
public static class WindowExtensions public static class WindowExtensions
{ {
public static WindowMessageListener CreateMessageListener(this Window window) => public static WindowMessageListener CreateMessageListener(this Window window) =>
+2 -2
View File
@@ -20,7 +20,7 @@ public class WindowHandler :
public Task Handle(Navigate<Window> args, public Task Handle(Navigate<Window> args,
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
if (args.Template is Window window) if (args.View is Window window)
{ {
if (window.Content is FrameworkElement content) if (window.Content is FrameworkElement content)
{ {
@@ -33,8 +33,8 @@ public class WindowHandler :
} }
} }
//ViewModelBinder.Bind(args.ViewModel, content);
window.Closed += HandleClosed; window.Closed += HandleClosed;
content.DataContext = args.Content;
} }
window.Activate(); window.Activate();
@@ -5,10 +5,11 @@ namespace Hyperbar.Widget.MediaController.Windows;
public partial class MediaButtonViewModel<TMediaButton>(IServiceProvider serviceProvider, public partial class MediaButtonViewModel<TMediaButton>(IServiceProvider serviceProvider,
IServiceFactory serviceFactory, IServiceFactory serviceFactory,
IMediator mediator, IPublisher publisher,
ISubscriber subscriber,
IDisposer disposer, IDisposer disposer,
IRelayCommand invokeCommand) : IRelayCommand invokeCommand) :
WidgetComponentViewModel(serviceProvider, serviceFactory, mediator, disposer), WidgetComponentViewModel(serviceProvider, serviceFactory, publisher, subscriber, disposer),
INotificationHandler<Changed<MediaButton<TMediaButton>>>, INotificationHandler<Changed<MediaButton<TMediaButton>>>,
IMediaButtonViewModel IMediaButtonViewModel
{ {
@@ -29,5 +30,5 @@ public partial class MediaButtonViewModel<TMediaButton>(IServiceProvider service
} }
public override async Task InitializeAsync() => public override async Task InitializeAsync() =>
await Mediator.PublishAsync<Request<TMediaButton>>(); await Publisher.PublishAsync<Request<TMediaButton>>();
} }
@@ -14,23 +14,24 @@ public class MediaController :
IDisposable IDisposable
{ {
private readonly IDisposer disposer; private readonly IDisposer disposer;
private readonly IMediator mediator; private readonly IPublisher publisher;
private readonly GlobalSystemMediaTransportControlsSession session; private readonly GlobalSystemMediaTransportControlsSession session;
private bool isNextEnabled; private bool isNextEnabled;
private bool isPreviousEnabled; private bool isPreviousEnabled;
private GlobalSystemMediaTransportControlsSessionPlaybackStatus playbackStatus; private GlobalSystemMediaTransportControlsSessionPlaybackStatus playbackStatus;
public MediaController(IMediator mediator, public MediaController(IPublisher publisher,
ISubscriber subscriber,
IDisposer disposer, IDisposer disposer,
GlobalSystemMediaTransportControlsSession session) GlobalSystemMediaTransportControlsSession session)
{ {
this.mediator = mediator; this.publisher = publisher;
this.disposer = disposer; this.disposer = disposer;
this.session = session; this.session = session;
disposer.Add(this); disposer.Add(this);
mediator.Subscribe(this); subscriber.Add(this);
session.MediaPropertiesChanged += OnMediaPropertiesChanged; session.MediaPropertiesChanged += OnMediaPropertiesChanged;
session.PlaybackInfoChanged += OnPlaybackInfoChanged; session.PlaybackInfoChanged += OnPlaybackInfoChanged;
@@ -117,7 +118,7 @@ public class MediaController :
buffer = memoryStream.ToArray(); buffer = memoryStream.ToArray();
} }
await mediator.PublishAsync(new Changed<MediaInformation>(new MediaInformation(mediaProperties.Title, await publisher.PublishAsync(new Changed<MediaInformation>(new MediaInformation(mediaProperties.Title,
mediaProperties.Artist, buffer))); mediaProperties.Artist, buffer)));
} }
catch catch
@@ -133,7 +134,7 @@ public class MediaController :
GlobalSystemMediaTransportControlsSessionPlaybackInfo playbackInfo = GlobalSystemMediaTransportControlsSessionPlaybackInfo playbackInfo =
session.GetPlaybackInfo(); session.GetPlaybackInfo();
await mediator.PublishAsync(new Changed<MediaButton<MediaPlayPauseButton>>(new await publisher.PublishAsync(new Changed<MediaButton<MediaPlayPauseButton>>(new
MediaButton<MediaPlayPauseButton>(playbackInfo.PlaybackStatus is MediaButton<MediaPlayPauseButton>(playbackInfo.PlaybackStatus is
GlobalSystemMediaTransportControlsSessionPlaybackStatus.Playing ? GlobalSystemMediaTransportControlsSessionPlaybackStatus.Playing ?
new MediaButtonPlaying() : new MediaButtonPlaying() :
@@ -142,7 +143,7 @@ public class MediaController :
bool isPreviousEnabled = playbackInfo.Controls.IsPreviousEnabled; bool isPreviousEnabled = playbackInfo.Controls.IsPreviousEnabled;
if (this.isPreviousEnabled != isPreviousEnabled) if (this.isPreviousEnabled != isPreviousEnabled)
{ {
await mediator.PublishAsync(new Changed<MediaButton<MediaPreviousButton>>(new await publisher.PublishAsync(new Changed<MediaButton<MediaPreviousButton>>(new
MediaButton<MediaPreviousButton>(isPreviousEnabled ? new MediaButtonEnabled() : MediaButton<MediaPreviousButton>(isPreviousEnabled ? new MediaButtonEnabled() :
new MediaButtonDisabled()))); new MediaButtonDisabled())));
@@ -152,7 +153,7 @@ public class MediaController :
bool isNextEnabled = playbackInfo.Controls.IsNextEnabled; bool isNextEnabled = playbackInfo.Controls.IsNextEnabled;
if (this.isNextEnabled != isNextEnabled) if (this.isNextEnabled != isNextEnabled)
{ {
await mediator.PublishAsync(new Changed<MediaButton<MediaNextButton>>(new await publisher.PublishAsync(new Changed<MediaButton<MediaNextButton>>(new
MediaButton<MediaNextButton>(isNextEnabled ? new MediaButtonEnabled() : MediaButton<MediaNextButton>(isNextEnabled ? new MediaButtonEnabled() :
new MediaButtonDisabled()))); new MediaButtonDisabled())));
@@ -2,7 +2,7 @@
namespace Hyperbar.Widget.MediaController.Windows; namespace Hyperbar.Widget.MediaController.Windows;
public class MediaControllerHandler(IMediator mediator, public class MediaControllerHandler(IPublisher publisher,
IServiceScopeProvider<MediaController> scopeProvider, IServiceScopeProvider<MediaController> scopeProvider,
ICache<MediaController, MediaControllerViewModel> cache) : ICache<MediaController, MediaControllerViewModel> cache) :
INotificationHandler<Create<MediaController>>, INotificationHandler<Create<MediaController>>,
@@ -18,7 +18,7 @@ public class MediaControllerHandler(IMediator mediator,
factory.Create(mediaController) is MediaControllerViewModel viewModel) factory.Create(mediaController) is MediaControllerViewModel viewModel)
{ {
cache.Add(mediaController, viewModel); cache.Add(mediaController, viewModel);
await mediator.PublishAsync(new Create<MediaControllerViewModel>(viewModel), cancellationToken); await publisher.PublishAsync(new Create<MediaControllerViewModel>(viewModel), cancellationToken);
} }
} }
@@ -28,7 +28,7 @@ public class MediaControllerHandler(IMediator mediator,
cache.TryGetValue(mediaController, out MediaControllerViewModel? viewModel) && cache.TryGetValue(mediaController, out MediaControllerViewModel? viewModel) &&
viewModel is not null) viewModel is not null)
{ {
await mediator.PublishAsync(new Remove<MediaControllerViewModel>(viewModel), cancellationToken); await publisher.PublishAsync(new Remove<MediaControllerViewModel>(viewModel), cancellationToken);
cache.Remove(mediaController); cache.Remove(mediaController);
} }
} }
@@ -3,7 +3,7 @@ using Windows.Media.Control;
namespace Hyperbar.Widget.MediaController.Windows; namespace Hyperbar.Widget.MediaController.Windows;
public class MediaControllerService(IMediator mediator, public class MediaControllerService(IPublisher publisher,
IFactory<GlobalSystemMediaTransportControlsSession, MediaController> factory) : IFactory<GlobalSystemMediaTransportControlsSession, MediaController> factory) :
IHostedService IHostedService
{ {
@@ -34,7 +34,7 @@ public class MediaControllerService(IMediator mediator,
{ {
if (factory.Create(session) is MediaController mediaController) if (factory.Create(session) is MediaController mediaController)
{ {
await mediator.PublishAsync(new Create<MediaController>(mediaController)); await publisher.PublishAsync(new Create<MediaController>(mediaController));
cache.Add(new KeyValuePair<GlobalSystemMediaTransportControlsSession, MediaController>(session, cache.Add(new KeyValuePair<GlobalSystemMediaTransportControlsSession, MediaController>(session,
mediaController)); mediaController));
} }
@@ -53,7 +53,7 @@ public class MediaControllerService(IMediator mediator,
{ {
if (!sessions.Any(x => x.SourceAppUserModelId == session.Key.SourceAppUserModelId)) if (!sessions.Any(x => x.SourceAppUserModelId == session.Key.SourceAppUserModelId))
{ {
await mediator.PublishAsync(new Remove<MediaController>(session.Value)); await publisher.PublishAsync(new Remove<MediaController>(session.Value));
cache.Remove(session); cache.Remove(session);
} }
} }
@@ -10,21 +10,22 @@ public class MediaControllerViewModel :
public MediaControllerViewModel(IViewModelTemplate template, public MediaControllerViewModel(IViewModelTemplate template,
IServiceProvider serviceProvider, IServiceProvider serviceProvider,
IServiceFactory serviceFactory, IServiceFactory serviceFactory,
IMediator mediator, IPublisher publisher,
IDisposer disposer) : base(serviceProvider, serviceFactory, mediator, disposer) ISubscriber subscriber,
IDisposer disposer) : base(serviceProvider, serviceFactory, publisher, subscriber, disposer)
{ {
Template = template; Template = template;
Add<MediaInformationViewModel>(); Add<MediaInformationViewModel>();
Add<MediaButtonViewModel<MediaPreviousButton>>(new RelayCommand(async () => Add<MediaButtonViewModel<MediaPreviousButton>>(new RelayCommand(async () =>
await mediator.PublishAsync<Request<MediaPrevious>>())); await publisher.PublishAsync<Request<MediaPrevious>>()));
Add<MediaButtonViewModel<MediaPlayPauseButton>>(new RelayCommand(async () => Add<MediaButtonViewModel<MediaPlayPauseButton>>(new RelayCommand(async () =>
await mediator.PublishAsync<Request<MediaPlayPause>>())); await publisher.PublishAsync<Request<MediaPlayPause>>()));
Add<MediaButtonViewModel<MediaNextButton>>(new RelayCommand(async () => Add<MediaButtonViewModel<MediaNextButton>>(new RelayCommand(async () =>
await mediator.PublishAsync<Request<MediaNext>>())); await publisher.PublishAsync<Request<MediaNext>>()));
} }
public IViewModelTemplate Template { get; } public IViewModelTemplate Template { get; }
@@ -5,10 +5,11 @@ namespace Hyperbar.Widget.MediaController.Windows;
public class MediaControllerWidgetViewModel(IViewModelTemplate template, public class MediaControllerWidgetViewModel(IViewModelTemplate template,
IServiceProvider serviceProvider, IServiceProvider serviceProvider,
IServiceFactory serviceFactory, IServiceFactory serviceFactory,
IMediator mediator, IPublisher publisher,
ISubscriber subscriber,
IDisposer disposer, IDisposer disposer,
IEnumerable<MediaControllerViewModel> items) : IEnumerable<MediaControllerViewModel> items) :
ObservableCollectionViewModel<MediaControllerViewModel>(serviceProvider, serviceFactory, mediator, disposer, items), ObservableCollectionViewModel<MediaControllerViewModel>(serviceProvider, serviceFactory, publisher, subscriber, disposer, items),
IWidgetViewModel IWidgetViewModel
{ {
public IViewModelTemplate Template => template; public IViewModelTemplate Template => template;
@@ -4,9 +4,10 @@ namespace Hyperbar.Widget.MediaController.Windows;
public partial class MediaInformationViewModel(IServiceProvider serviceProvider, public partial class MediaInformationViewModel(IServiceProvider serviceProvider,
IServiceFactory serviceFactory, IServiceFactory serviceFactory,
IMediator mediator, IPublisher publisher,
ISubscriber subscriber,
IDisposer disposer) : IDisposer disposer) :
WidgetComponentViewModel(serviceProvider, serviceFactory, mediator, disposer), WidgetComponentViewModel(serviceProvider, serviceFactory, publisher, subscriber, disposer),
INotificationHandler<Changed<MediaInformation>> INotificationHandler<Changed<MediaInformation>>
{ {
[ObservableProperty] [ObservableProperty]
@@ -32,5 +33,5 @@ public partial class MediaInformationViewModel(IServiceProvider serviceProvider,
} }
public override async Task InitializeAsync() => public override async Task InitializeAsync() =>
await Mediator.PublishAsync<Request<MediaInformation>>(); await Publisher.PublishAsync<Request<MediaInformation>>();
} }
@@ -1,8 +1,6 @@
using Hyperbar.Widget; namespace Hyperbar.Widget.Primary.Windows;
namespace Hyperbar.Widget.Primary.Windows; public class PrimaryWidgetConfigurationHandler(IPublisher publisher,
public class PrimaryWidgetConfigurationHandler(IMediator mediator,
PrimaryWidgetConfiguration configuration, PrimaryWidgetConfiguration configuration,
IFactory<PrimaryCommandConfiguration, IWidgetComponentViewModel?> factory, IFactory<PrimaryCommandConfiguration, IWidgetComponentViewModel?> factory,
IProvider<PrimaryCommandConfiguration, IWidgetComponentViewModel?> provider, IProvider<PrimaryCommandConfiguration, IWidgetComponentViewModel?> provider,
@@ -44,7 +42,7 @@ public class PrimaryWidgetConfigurationHandler(IMediator mediator,
if (moved.Value is PrimaryCommandConfiguration configuration && if (moved.Value is PrimaryCommandConfiguration configuration &&
provider.Get(configuration) is IWidgetComponentViewModel viewModel) provider.Get(configuration) is IWidgetComponentViewModel viewModel)
{ {
await mediator.PublishAsync(new Move<IWidgetComponentViewModel>(configuration.Order, viewModel), await publisher.PublishAsync(new Move<IWidgetComponentViewModel>(configuration.Order, viewModel),
moved.Key.ParentId == Guid.Empty ? nameof(PrimaryWidgetViewModel) : moved.Key.ParentId, moved.Key.ParentId == Guid.Empty ? nameof(PrimaryWidgetViewModel) : moved.Key.ParentId,
cancellationToken); cancellationToken);
@@ -61,8 +59,7 @@ public class PrimaryWidgetConfigurationHandler(IMediator mediator,
if (added.Value is PrimaryCommandConfiguration configuration && if (added.Value is PrimaryCommandConfiguration configuration &&
factory.Create(configuration) is IWidgetComponentViewModel viewModel) factory.Create(configuration) is IWidgetComponentViewModel viewModel)
{ {
await mediator.PublishAsync( await publisher.PublishAsync(new Insert<IWidgetComponentViewModel>(configuration.Order, viewModel),
new Insert<IWidgetComponentViewModel>(configuration.Order, viewModel),
added.Key.ParentId == Guid.Empty ? nameof(PrimaryWidgetViewModel) : added.Key.ParentId, added.Key.ParentId == Guid.Empty ? nameof(PrimaryWidgetViewModel) : added.Key.ParentId,
cancellationToken); cancellationToken);
@@ -78,8 +75,7 @@ public class PrimaryWidgetConfigurationHandler(IMediator mediator,
if (removed.Value is PrimaryCommandConfiguration configuration && if (removed.Value is PrimaryCommandConfiguration configuration &&
provider.Get(configuration) is IWidgetComponentViewModel viewModel) provider.Get(configuration) is IWidgetComponentViewModel viewModel)
{ {
await mediator.PublishAsync( await publisher.PublishAsync(new Remove<IWidgetComponentViewModel>(viewModel),
new Remove<IWidgetComponentViewModel>(viewModel),
removed.Key.ParentId == Guid.Empty ? nameof(PrimaryWidgetViewModel) : removed.Key.ParentId, removed.Key.ParentId == Guid.Empty ? nameof(PrimaryWidgetViewModel) : removed.Key.ParentId,
cancellationToken); cancellationToken);
@@ -5,7 +5,8 @@ namespace Hyperbar.Widget.Primary.Windows;
[NotificationHandler(nameof(PrimaryWidgetViewModel))] [NotificationHandler(nameof(PrimaryWidgetViewModel))]
public class PrimaryWidgetViewModel(IServiceProvider serviceProvider, public class PrimaryWidgetViewModel(IServiceProvider serviceProvider,
IServiceFactory serviceFactory, IServiceFactory serviceFactory,
IMediator mediator, IPublisher publisher,
ISubscriber subscriber,
IDisposer disposer) : IDisposer disposer) :
ObservableCollectionViewModel<IWidgetComponentViewModel>(serviceProvider, serviceFactory, mediator, disposer), ObservableCollectionViewModel<IWidgetComponentViewModel>(serviceProvider, serviceFactory, publisher, subscriber, disposer),
IWidgetViewModel; IWidgetViewModel;
@@ -1,14 +1,13 @@
using Hyperbar.Widget; namespace Hyperbar.Widget.Primary.Windows;
namespace Hyperbar.Widget.Primary.Windows;
public class WidgetComponentViewModelEnumerator(PrimaryWidgetConfiguration configuration, public class WidgetComponentViewModelEnumerator(PrimaryWidgetConfiguration configuration,
IMediator mediator, IPublisher publisher,
IFactory<PrimaryCommandConfiguration, IWidgetComponentViewModel?> factory, IFactory<PrimaryCommandConfiguration, IWidgetComponentViewModel?> factory,
ICache<(Guid ParentId, Guid Id), PrimaryCommandConfiguration> cache) : ICache<(Guid ParentId, Guid Id), PrimaryCommandConfiguration> cache) :
INotificationHandler<Enumerate<IWidgetComponentViewModel>> INotificationHandler<Enumerate<IWidgetComponentViewModel>>
{ {
public async Task Handle(Enumerate<IWidgetComponentViewModel> notification, CancellationToken cancellationToken) public async Task Handle(Enumerate<IWidgetComponentViewModel> notification,
CancellationToken cancellationToken)
{ {
Stack<(Guid, List<PrimaryCommandConfiguration>)> stack = new(); Stack<(Guid, List<PrimaryCommandConfiguration>)> stack = new();
stack.Push((Guid.Empty, configuration.Commands)); stack.Push((Guid.Empty, configuration.Commands));
@@ -30,7 +29,7 @@ public class WidgetComponentViewModelEnumerator(PrimaryWidgetConfiguration confi
{ {
if (factory.Create(item) is IWidgetComponentViewModel viewModel) if (factory.Create(item) is IWidgetComponentViewModel viewModel)
{ {
await mediator.PublishAsync(new Create<IWidgetComponentViewModel>(viewModel), nameof(PrimaryWidgetViewModel), await publisher.PublishAsync(new Create<IWidgetComponentViewModel>(viewModel), nameof(PrimaryWidgetViewModel),
cancellationToken); cancellationToken);
} }
} }
+3 -2
View File
@@ -6,12 +6,13 @@ namespace Hyperbar.Widget;
[NotificationHandler(nameof(Id))] [NotificationHandler(nameof(Id))]
public partial class WidgetButtonViewModel(IServiceProvider serviceProvider, public partial class WidgetButtonViewModel(IServiceProvider serviceProvider,
IServiceFactory serviceFactory, IServiceFactory serviceFactory,
IMediator mediator, IPublisher publisher,
ISubscriber subscriber,
IDisposer disposer, IDisposer disposer,
Guid id, Guid id,
string? text = null, string? text = null,
string? icon = null, string? icon = null,
RelayCommand? invokeCommand = null) : WidgetComponentViewModel(serviceProvider, serviceFactory, mediator, disposer) RelayCommand? invokeCommand = null) : WidgetComponentViewModel(serviceProvider, serviceFactory, publisher, subscriber, disposer)
{ {
[ObservableProperty] [ObservableProperty]
private string? icon = icon; private string? icon = icon;
+6 -4
View File
@@ -6,17 +6,19 @@ public partial class WidgetComponentViewModel :
{ {
public WidgetComponentViewModel(IServiceProvider serviceProvider, public WidgetComponentViewModel(IServiceProvider serviceProvider,
IServiceFactory serviceFactory, IServiceFactory serviceFactory,
IMediator mediator, IPublisher publisher,
ISubscriber subscriber,
IDisposer disposer, IDisposer disposer,
IEnumerable<IWidgetComponentViewModel> items) : base(serviceProvider, serviceFactory, mediator, disposer, items) IEnumerable<IWidgetComponentViewModel> items) : base(serviceProvider, serviceFactory, publisher, subscriber, disposer, items)
{ {
} }
public WidgetComponentViewModel(IServiceProvider serviceProvider, public WidgetComponentViewModel(IServiceProvider serviceProvider,
IServiceFactory serviceFactory, IServiceFactory serviceFactory,
IMediator mediator, IPublisher publisher,
IDisposer disposer) : base(serviceProvider, serviceFactory, mediator, disposer) ISubscriber subscriber,
IDisposer disposer) : base(serviceProvider, serviceFactory, publisher, subscriber, disposer)
{ {
} }
+2 -2
View File
@@ -6,7 +6,7 @@ namespace Hyperbar.Widget;
public class WidgetExtensionEnumerator(IFactory<Type, IWidget> factory, public class WidgetExtensionEnumerator(IFactory<Type, IWidget> factory,
IHostEnvironment hostEnvironment, IHostEnvironment hostEnvironment,
IMediator mediator) : IPublisher publisher) :
INotificationHandler<Enumerate<WidgetExtension>> INotificationHandler<Enumerate<WidgetExtension>>
{ {
public Task Handle(Enumerate<WidgetExtension> args, public Task Handle(Enumerate<WidgetExtension> args,
@@ -29,7 +29,7 @@ public class WidgetExtensionEnumerator(IFactory<Type, IWidget> factory,
{ {
if (factory.Create(widgetType) is IWidget widget) if (factory.Create(widgetType) is IWidget widget)
{ {
await mediator.PublishAsync(new Create<WidgetExtension>(new WidgetExtension(widget, await publisher.PublishAsync(new Create<WidgetExtension>(new WidgetExtension(widget,
new WidgetAssembly(assembly))), cancellationToken); new WidgetAssembly(assembly))), cancellationToken);
} }
} }
+2 -2
View File
@@ -3,7 +3,7 @@
namespace Hyperbar.Widget; namespace Hyperbar.Widget;
public class WidgetExtensionHandler(IServiceProvider provider, public class WidgetExtensionHandler(IServiceProvider provider,
IMediator mediator, IPublisher publisher,
IProxyServiceCollection<IWidgetBuilder> typedServices) : IProxyServiceCollection<IWidgetBuilder> typedServices) :
INotificationHandler<Create<WidgetExtension>> INotificationHandler<Create<WidgetExtension>>
{ {
@@ -22,7 +22,7 @@ public class WidgetExtensionHandler(IServiceProvider provider,
}); });
IWidgetHost host = builder.Build(); IWidgetHost host = builder.Build();
await mediator.PublishAsync(new Create<IWidgetHost>(host), await publisher.PublishAsync(new Create<IWidgetHost>(host),
cancellationToken); cancellationToken);
} }
} }
@@ -1,8 +1,8 @@
namespace Hyperbar.Widget; namespace Hyperbar.Widget;
public class WidgetExtensionInitializer(IMediator mediator) : public class WidgetExtensionInitializer(IPublisher publisher) :
IInitializer IInitializer
{ {
public async Task InitializeAsync() => public async Task InitializeAsync() =>
await mediator.PublishAsync<Enumerate<WidgetExtension>>(); await publisher.PublishAsync<Enumerate<WidgetExtension>>();
} }
+5 -5
View File
@@ -7,17 +7,17 @@ public sealed class WidgetHost :
IWidgetHost IWidgetHost
{ {
private readonly IServiceProvider services; private readonly IServiceProvider services;
private readonly IMediator mediator; private readonly IPublisher publisher;
private readonly IProxyService<IMediator> proxyMediator; private readonly IProxyService<IMediator> proxyMediator;
private readonly IEnumerable<IHostedService> hostedServices; private readonly IEnumerable<IHostedService> hostedServices;
public WidgetHost(IServiceProvider services, public WidgetHost(IServiceProvider services,
IMediator mediator, IPublisher publisher,
IProxyService<IMediator> proxyMediator, IProxyService<IMediator> proxyMediator,
IEnumerable<IHostedService> hostedServices) IEnumerable<IHostedService> hostedServices)
{ {
this.services = services; this.services = services;
this.mediator = mediator; this.publisher = publisher;
this.proxyMediator = proxyMediator; this.proxyMediator = proxyMediator;
this.hostedServices = hostedServices; this.hostedServices = hostedServices;
} }
@@ -41,11 +41,11 @@ public sealed class WidgetHost :
if (proxyMediator.Proxy is IMediator mediator) if (proxyMediator.Proxy is IMediator mediator)
{ {
await mediator.PublishAsync(new Started<IWidgetHost>(this), await publisher.PublishAsync(new Started<IWidgetHost>(this),
cancellationToken); cancellationToken);
} }
await this.mediator.PublishAsync(new Started<IWidgetHost>(this), await this.publisher.PublishAsync(new Started<IWidgetHost>(this),
cancellationToken); cancellationToken);
} }
+3 -2
View File
@@ -6,12 +6,13 @@ namespace Hyperbar.Widget;
[NotificationHandler(nameof(Id))] [NotificationHandler(nameof(Id))]
public partial class WidgetMenuViewModel(IServiceProvider serviceProvider, public partial class WidgetMenuViewModel(IServiceProvider serviceProvider,
IServiceFactory serviceFactory, IServiceFactory serviceFactory,
IMediator mediator, IPublisher publisher,
ISubscriber subscriber,
IDisposer disposer, IDisposer disposer,
Guid id = default, Guid id = default,
string? text = null, string? text = null,
string? icon = null, string? icon = null,
RelayCommand? command = null) : WidgetComponentViewModel(serviceProvider, serviceFactory, mediator, disposer) RelayCommand? command = null) : WidgetComponentViewModel(serviceProvider, serviceFactory, publisher, subscriber, disposer)
{ {
[ObservableProperty] [ObservableProperty]
private IRelayCommand? click = command; private IRelayCommand? click = command;
@@ -6,13 +6,14 @@ namespace Hyperbar.Widget;
[NotificationHandler(nameof(Id))] [NotificationHandler(nameof(Id))]
public partial class WidgetSplitButtonViewModel(IServiceProvider serviceProvider, public partial class WidgetSplitButtonViewModel(IServiceProvider serviceProvider,
IServiceFactory serviceFactory, IServiceFactory serviceFactory,
IMediator mediator, IPublisher publisher,
ISubscriber subscriber,
IDisposer disposer, IDisposer disposer,
IEnumerable<IWidgetComponentViewModel> items, IEnumerable<IWidgetComponentViewModel> items,
Guid id = default, Guid id = default,
string? text = null, string? text = null,
string? icon = null, string? icon = null,
RelayCommand? command = null) : WidgetComponentViewModel(serviceProvider, serviceFactory, mediator, disposer, items) RelayCommand? command = null) : WidgetComponentViewModel(serviceProvider, serviceFactory, publisher, subscriber, disposer, items)
{ {
[ObservableProperty] [ObservableProperty]
private IRelayCommand? click = command; private IRelayCommand? click = command;
+2 -2
View File
@@ -2,7 +2,7 @@
namespace Hyperbar.Widget; namespace Hyperbar.Widget;
public class WidgetStartedHandler(IMediator mediator) : public class WidgetStartedHandler(IPublisher publisher) :
INotificationHandler<Started<IWidgetHost>> INotificationHandler<Started<IWidgetHost>>
{ {
public async Task Handle(Started<IWidgetHost> notification, public async Task Handle(Started<IWidgetHost> notification,
@@ -12,7 +12,7 @@ public class WidgetStartedHandler(IMediator mediator) :
{ {
if (host.Services.GetService<IWidgetViewModel>() is IWidgetViewModel viewModel) if (host.Services.GetService<IWidgetViewModel>() is IWidgetViewModel viewModel)
{ {
await mediator.PublishAsync(new Create<IWidgetViewModel>(viewModel), await publisher.PublishAsync(new Create<IWidgetViewModel>(viewModel),
nameof(IWidgetHostViewModel), cancellationToken); nameof(IWidgetHostViewModel), cancellationToken);
} }
} }
+2 -2
View File
@@ -3,7 +3,7 @@
namespace Hyperbar.Widget; namespace Hyperbar.Widget;
public class WidgetViewModelEnumerator(IWidgetHost host, public class WidgetViewModelEnumerator(IWidgetHost host,
IMediator mediator) : IPublisher publisher) :
INotificationHandler<Enumerate<IWidgetViewModel>> INotificationHandler<Enumerate<IWidgetViewModel>>
{ {
public async Task Handle(Enumerate<IWidgetViewModel> notification, public async Task Handle(Enumerate<IWidgetViewModel> notification,
@@ -13,7 +13,7 @@ public class WidgetViewModelEnumerator(IWidgetHost host,
{ {
foreach (IWidgetViewModel viewModel in viewModels) foreach (IWidgetViewModel viewModel in viewModels)
{ {
await mediator.PublishAsync(new Create<IWidgetViewModel>(viewModel), await publisher.PublishAsync(new Create<IWidgetViewModel>(viewModel),
nameof(IWidgetHostViewModel), cancellationToken); nameof(IWidgetHostViewModel), cancellationToken);
} }
} }
+1 -5
View File
@@ -2,16 +2,12 @@
<Application <Application
x:Class="Hyperbar.Windows.App" x:Class="Hyperbar.Windows.App"
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:ui="using:Hyperbar.UI.Windows">
<Application.Resources> <Application.Resources>
<ResourceDictionary> <ResourceDictionary>
<ResourceDictionary.MergedDictionaries> <ResourceDictionary.MergedDictionaries>
<XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" /> <XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" />
</ResourceDictionary.MergedDictionaries> </ResourceDictionary.MergedDictionaries>
<DataTemplate x:Key="DefaultDataTemplate">
<ui:ViewModelTemplatePresenter />
</DataTemplate>
</ResourceDictionary> </ResourceDictionary>
</Application.Resources> </Application.Resources>
</Application> </Application>
+3 -2
View File
@@ -10,8 +10,9 @@ public partial class ApplicationBarViewModel :
public ApplicationBarViewModel(IViewModelTemplate template, public ApplicationBarViewModel(IViewModelTemplate template,
IServiceProvider serviceProvider, IServiceProvider serviceProvider,
IServiceFactory serviceFactory, IServiceFactory serviceFactory,
IMediator mediator, IPublisher publisher,
IDisposer disposer) : base(serviceProvider, serviceFactory, mediator, disposer) ISubscriber subscriber,
IDisposer disposer) : base(serviceProvider, serviceFactory, publisher, subscriber, disposer)
{ {
Template = template; Template = template;
@@ -2,9 +2,10 @@
public class GeneralSettingsNavigationViewModel(IServiceProvider serviceProvider, public class GeneralSettingsNavigationViewModel(IServiceProvider serviceProvider,
IServiceFactory serviceFactory, IServiceFactory serviceFactory,
IMediator mediator, IPublisher publisher,
ISubscriber subscriber,
IDisposer disposer, IDisposer disposer,
string text) : string text) :
NavigationViewModel(serviceProvider, serviceFactory, mediator, disposer, text) NavigationViewModel(serviceProvider, serviceFactory, publisher, subscriber, disposer, text)
{ {
} }
+3 -2
View File
@@ -7,10 +7,11 @@ namespace Hyperbar.Widget;
public partial class PrimaryViewModel(IViewModelTemplate template, public partial class PrimaryViewModel(IViewModelTemplate template,
IServiceProvider serviceProvider, IServiceProvider serviceProvider,
IServiceFactory serviceFactory, IServiceFactory serviceFactory,
IMediator mediator, IPublisher publisher,
ISubscriber subscriber,
IDisposer disposer, IDisposer disposer,
int index) : int index) :
ObservableCollectionViewModel<IWidgetViewModel>(serviceProvider, serviceFactory, mediator, disposer), ObservableCollectionViewModel<IWidgetViewModel>(serviceProvider, serviceFactory, publisher, subscriber, disposer),
IWidgetHostViewModel IWidgetHostViewModel
{ {
[ObservableProperty] [ObservableProperty]
+3 -2
View File
@@ -13,9 +13,10 @@ public partial class SecondaryViewModel :
public SecondaryViewModel(IViewModelTemplate template, public SecondaryViewModel(IViewModelTemplate template,
IServiceProvider serviceProvider, IServiceProvider serviceProvider,
IServiceFactory serviceFactory, IServiceFactory serviceFactory,
IMediator mediator, IPublisher publisher,
ISubscriber subscriber,
IDisposer disposer, IDisposer disposer,
int index) : base(serviceProvider, serviceFactory, mediator, disposer) int index) : base(serviceProvider, serviceFactory, publisher, subscriber, disposer)
{ {
Template = template; Template = template;
this.index = index; this.index = index;
+2 -2
View File
@@ -5,9 +5,9 @@ namespace Hyperbar.Windows;
public partial class SettingsButtonViewModel(IViewModelTemplate template, public partial class SettingsButtonViewModel(IViewModelTemplate template,
IServiceProvider serviceProvider, IServiceProvider serviceProvider,
IServiceFactory serviceFactory, IServiceFactory serviceFactory,
IMediator mediator, IPublisher publisher,
IDisposer disposer) : IDisposer disposer) :
ObservableViewModel(serviceProvider, serviceFactory, mediator, disposer) ObservableViewModel(serviceProvider, serviceFactory, publisher, disposer)
{ {
public IViewModelTemplate Template => template; public IViewModelTemplate Template => template;
} }
+3 -2
View File
@@ -8,8 +8,9 @@ public partial class SettingsViewModel :
public SettingsViewModel(IViewModelTemplate template, public SettingsViewModel(IViewModelTemplate template,
IServiceProvider serviceProvider, IServiceProvider serviceProvider,
IServiceFactory serviceFactory, IServiceFactory serviceFactory,
IMediator mediator, IPublisher publisher,
IDisposer disposer) : base(serviceProvider, serviceFactory, mediator, disposer) ISubscriber subscriber,
IDisposer disposer) : base(serviceProvider, serviceFactory, publisher, subscriber, disposer)
{ {
Template = template; Template = template;
@@ -2,9 +2,10 @@
public class WidgetNavigationViewModel(IServiceProvider serviceProvider, public class WidgetNavigationViewModel(IServiceProvider serviceProvider,
IServiceFactory serviceFactory, IServiceFactory serviceFactory,
IMediator mediator, IPublisher publisher,
ISubscriber subscriber,
IDisposer disposer, IDisposer disposer,
string text) : string text) :
NavigationViewModel(serviceProvider, serviceFactory, mediator, disposer, text) NavigationViewModel(serviceProvider, serviceFactory, publisher, subscriber, disposer, text)
{ {
} }
@@ -2,10 +2,11 @@
public class WidgetSettingsNavigationViewModel(IServiceProvider serviceProvider, public class WidgetSettingsNavigationViewModel(IServiceProvider serviceProvider,
IServiceFactory serviceFactory, IServiceFactory serviceFactory,
IMediator mediator, IPublisher publisher,
ISubscriber subscriber,
IDisposer disposer, IDisposer disposer,
string text) : string text) :
NavigationViewModel<WidgetNavigationViewModel>(serviceProvider, serviceFactory, mediator, disposer, text) NavigationViewModel<WidgetNavigationViewModel>(serviceProvider, serviceFactory, publisher, subscriber, disposer, text)
{ {
} }
@@ -1,6 +1,6 @@
namespace Hyperbar; namespace Hyperbar;
public class ConfigurationInitializer<TConfiguration>(IMediator mediator, public class ConfigurationInitializer<TConfiguration>(IPublisher publisher,
IConfigurationMonitor<TConfiguration> monitor, IConfigurationMonitor<TConfiguration> monitor,
IConfigurationReader<TConfiguration> reader, IConfigurationReader<TConfiguration> reader,
IConfigurationWriter<TConfiguration> writer, IConfigurationWriter<TConfiguration> writer,
@@ -21,7 +21,7 @@ public class ConfigurationInitializer<TConfiguration>(IMediator mediator,
} }
} }
await mediator.PublishAsync(new Changed<TConfiguration>(configuration)); await publisher.PublishAsync(new Changed<TConfiguration>(configuration));
await monitor.InitializeAsync(); await monitor.InitializeAsync();
} }
} }
@@ -2,7 +2,7 @@
public class ConfigurationMonitor<TConfiguration>(IConfigurationFile<TConfiguration> configurationFile, public class ConfigurationMonitor<TConfiguration>(IConfigurationFile<TConfiguration> configurationFile,
IConfigurationReader<TConfiguration> reader, IConfigurationReader<TConfiguration> reader,
IMediator mediator) : IPublisher publisher) :
IConfigurationMonitor<TConfiguration> IConfigurationMonitor<TConfiguration>
where TConfiguration : where TConfiguration :
class class
@@ -16,7 +16,7 @@ public class ConfigurationMonitor<TConfiguration>(IConfigurationFile<TConfigurat
{ {
if (reader.Read() is { } configuration) if (reader.Read() is { } configuration)
{ {
await mediator.PublishAsync(new Changed<TConfiguration>(configuration)); await publisher.PublishAsync(new Changed<TConfiguration>(configuration));
} }
} }
@@ -1,6 +1,6 @@
namespace Hyperbar; namespace Hyperbar;
public class ConfigurationValueChangedNotification<TConfiguration, TValue>(IMediator mediator, public class ConfigurationValueChangedNotification<TConfiguration, TValue>(IPublisher publisher,
Func<TConfiguration, Action<TValue>> factory) : Func<TConfiguration, Action<TValue>> factory) :
IConfigurationValueChangedNotification<TConfiguration> IConfigurationValueChangedNotification<TConfiguration>
where TConfiguration : where TConfiguration :
@@ -18,7 +18,7 @@ public class ConfigurationValueChangedNotification<TConfiguration, TValue>(IMedi
if (value is null || !value.Equals(newValue)) if (value is null || !value.Equals(newValue))
{ {
value = newValue; value = newValue;
await mediator.PublishAsync(new Changed<TValue>(value)); await publisher.PublishAsync(new Changed<TValue>(value));
} }
} }
} }
@@ -19,7 +19,7 @@ public static class IServiceCollectionExtensions
class, new() class, new()
{ {
services.AddSingleton<IConfigurationValueChangedNotification<TConfiguration>>(provider => services.AddSingleton<IConfigurationValueChangedNotification<TConfiguration>>(provider =>
new ConfigurationValueChangedNotification<TConfiguration, TValue>(provider.GetRequiredService<IMediator>(), new ConfigurationValueChangedNotification<TConfiguration, TValue>(provider.GetRequiredService<IPublisher>(),
factory)); factory));
return services; return services;
@@ -237,18 +237,6 @@ public static class IServiceCollectionExtensions
return services; return services;
} }
public static IServiceCollection AddNotificationRelay<TFromNotification,
TToNotification>(this IServiceCollection services)
where TFromNotification :
INotification
where TToNotification :
INotification, new()
{
return services.AddHandler<NotficationRelayHandler<TFromNotification,
TToNotification>>();
}
public static IServiceCollection AddRange(this IServiceCollection services, public static IServiceCollection AddRange(this IServiceCollection services,
IServiceCollection fromServices) IServiceCollection fromServices)
{ {
+23
View File
@@ -0,0 +1,23 @@
using System.Runtime.CompilerServices;
namespace Hyperbar;
public class AsyncLock(int initial = 1,
int maximum = 1) :
IDisposable
{
private readonly SemaphoreSlim semaphore = new(initial, maximum);
public void Dispose()
{
semaphore.Release();
}
public TaskAwaiter<AsyncLock> GetAwaiter() => LockAsync().GetAwaiter();
private async Task<AsyncLock> LockAsync()
{
await semaphore.WaitAsync();
return this;
}
}
+7 -6
View File
@@ -11,24 +11,25 @@ public class Cache<TValue>(IDisposer disposer) :
public void Add(TValue value) public void Add(TValue value)
{ {
disposer.Add(value!, Disposable.Create(() => if (value is null)
{ {
Remove(value); return;
})); }
disposer.Add(value, Disposable.Create(() => Remove(value)));
cache.Add(value); cache.Add(value);
} }
public void Clear() => cache.Clear(); public void Clear() => cache.Clear();
public System.Collections.Generic.IEnumerator<TValue> GetEnumerator() => cache.GetEnumerator(); public IEnumerator<TValue> GetEnumerator() => cache.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public bool Remove(TValue value) => cache.Remove(value); public bool Remove(TValue value) => cache.Remove(value);
} }
public class Cache<TKey, TValue>(IDisposer disposer) : public class Cache<TKey, TValue> :
ICache<TKey, TValue> ICache<TKey, TValue>
where TKey : where TKey :
notnull notnull
@@ -47,7 +48,7 @@ public class Cache<TKey, TValue>(IDisposer disposer) :
public bool ContainsKey(TKey key) => cache.ContainsKey(key); public bool ContainsKey(TKey key) => cache.ContainsKey(key);
public System.Collections.Generic.IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() => cache.GetEnumerator(); public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() => cache.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
+1 -22
View File
@@ -1,30 +1,9 @@
using System.Runtime.CompilerServices; using System.Reactive.Disposables;
using System.Reactive.Disposables;
using System.Collections; using System.Collections;
using System.Collections.Concurrent; using System.Collections.Concurrent;
namespace Hyperbar; namespace Hyperbar;
public class AsyncLock(int initial = 1,
int maximum = 1) : IDisposable
{
private readonly SemaphoreSlim semaphore = new(initial, maximum);
public void Dispose()
{
semaphore.Release();
}
public TaskAwaiter<AsyncLock> GetAwaiter() => LockAsync().GetAwaiter();
private async Task<AsyncLock> LockAsync()
{
await semaphore.WaitAsync();
return this;
}
}
public class Disposer : public class Disposer :
IDisposer IDisposer
{ {
-6
View File
@@ -1,6 +0,0 @@
namespace Hyperbar;
public interface IEnumerator<TItem>
{
IEnumerable<TItem?> Get();
}
+1 -1
View File
@@ -6,7 +6,7 @@ public interface IObservableViewModel :
{ {
public IDisposer Disposer { get; } public IDisposer Disposer { get; }
public IMediator Mediator { get; } public IPublisher Publisher { get; }
public IServiceFactory ServiceFactory { get; } public IServiceFactory ServiceFactory { get; }
+1 -1
View File
@@ -4,5 +4,5 @@ namespace Hyperbar;
public record Navigate(object Key) : public record Navigate(object Key) :
INotification; INotification;
public record Navigate<TTemplate>(TTemplate Template, object Content) : public record Navigate<TView>(TView View, object ViewModel) :
INotification; INotification;
+4 -4
View File
@@ -7,16 +7,16 @@ public class NavigateHandler :
{ {
private readonly IViewModelTemplateDescriptorProvider contentTemplateDescriptors; private readonly IViewModelTemplateDescriptorProvider contentTemplateDescriptors;
private readonly IServiceProvider provider; private readonly IServiceProvider provider;
private readonly IMediator mediator; private readonly IPublisher publisher;
private readonly IEnumerable<INavigationDescriptor> navigationDescriptors; private readonly IEnumerable<INavigationDescriptor> navigationDescriptors;
public NavigateHandler(IServiceProvider provider, public NavigateHandler(IServiceProvider provider,
IMediator mediator, IPublisher publisher,
IEnumerable<INavigationDescriptor> navigationDescriptors, IEnumerable<INavigationDescriptor> navigationDescriptors,
IViewModelTemplateDescriptorProvider contentTemplateDescriptors) IViewModelTemplateDescriptorProvider contentTemplateDescriptors)
{ {
this.provider = provider; this.provider = provider;
this.mediator = mediator; this.publisher = publisher;
this.navigationDescriptors = navigationDescriptors; this.navigationDescriptors = navigationDescriptors;
this.contentTemplateDescriptors = contentTemplateDescriptors; this.contentTemplateDescriptors = contentTemplateDescriptors;
} }
@@ -43,7 +43,7 @@ public class NavigateHandler :
if (Activator.CreateInstance(navigateType, if (Activator.CreateInstance(navigateType,
new object[] { template, content }) is object navigate) new object[] { template, content }) is object navigate)
{ {
await mediator.PublishAsync(navigate, cancellationToken); await publisher.PublishAsync(navigate, cancellationToken);
} }
} }
} }
+11 -14
View File
@@ -2,29 +2,26 @@
namespace Hyperbar; namespace Hyperbar;
public partial class NavigationViewModel : public partial class NavigationViewModel(IServiceProvider serviceProvider,
ObservableCollectionViewModel<INavigationViewModel>, IServiceFactory serviceFactory,
IPublisher publisher,
ISubscriber subscriber,
IDisposer disposer,
string text) :
ObservableCollectionViewModel<INavigationViewModel>(serviceProvider, serviceFactory, publisher, subscriber, disposer),
INavigationViewModel INavigationViewModel
{ {
[ObservableProperty] [ObservableProperty]
private string? text; private string? text = text;
public NavigationViewModel(IServiceProvider serviceProvider,
IServiceFactory serviceFactory,
IMediator mediator,
IDisposer disposer,
string text) : base(serviceProvider, serviceFactory, mediator, disposer)
{
this.text = text;
}
} }
public partial class NavigationViewModel<TNavigationViewModel>(IServiceProvider serviceProvider, public partial class NavigationViewModel<TNavigationViewModel>(IServiceProvider serviceProvider,
IServiceFactory serviceFactory, IServiceFactory serviceFactory,
IMediator mediator, IPublisher publisher,
ISubscriber subscriber,
IDisposer disposer, IDisposer disposer,
string text) : string text) :
ObservableCollectionViewModel<TNavigationViewModel>(serviceProvider, serviceFactory, mediator, disposer), ObservableCollectionViewModel<TNavigationViewModel>(serviceProvider, serviceFactory, publisher, subscriber, disposer),
INavigationViewModel INavigationViewModel
where TNavigationViewModel : where TNavigationViewModel :
INavigationViewModel INavigationViewModel
@@ -27,31 +27,33 @@ public partial class ObservableCollectionViewModel<TViewModel> :
public ObservableCollectionViewModel(IServiceProvider serviceProvider, public ObservableCollectionViewModel(IServiceProvider serviceProvider,
IServiceFactory serviceFactory, IServiceFactory serviceFactory,
IMediator mediator, IPublisher publisher,
ISubscriber subscriber,
IDisposer disposer) IDisposer disposer)
{ {
ServiceProvider = serviceProvider; ServiceProvider = serviceProvider;
ServiceFactory = serviceFactory; ServiceFactory = serviceFactory;
Mediator = mediator; Publisher = publisher;
Disposer = disposer; Disposer = disposer;
mediator.Subscribe(this); subscriber.Add(this);
collection.CollectionChanged += OnCollectionChanged; collection.CollectionChanged += OnCollectionChanged;
} }
public ObservableCollectionViewModel(IServiceProvider serviceProvider, public ObservableCollectionViewModel(IServiceProvider serviceProvider,
IServiceFactory serviceFactory, IServiceFactory serviceFactory,
IMediator mediator, IPublisher publisher,
ISubscriber subscriber,
IDisposer disposer, IDisposer disposer,
IEnumerable<TViewModel> items) IEnumerable<TViewModel> items)
{ {
ServiceProvider = serviceProvider; ServiceProvider = serviceProvider;
ServiceFactory = serviceFactory; ServiceFactory = serviceFactory;
Mediator = mediator; Publisher = publisher;
Disposer = disposer; Disposer = disposer;
mediator.Subscribe(this); subscriber.Add(this);
collection.CollectionChanged += OnCollectionChanged; collection.CollectionChanged += OnCollectionChanged;
AddRange(items); AddRange(items);
@@ -74,14 +76,14 @@ public partial class ObservableCollectionViewModel<TViewModel> :
bool ICollection.IsSynchronized => false; bool ICollection.IsSynchronized => false;
public IMediator Mediator { get; private set; } public IPublisher Publisher { get; private set; }
public IServiceFactory ServiceFactory { get; private set; } public IServiceFactory ServiceFactory { get; private set; }
object ICollection.SyncRoot => this;
public IServiceProvider ServiceProvider { get; private set; } public IServiceProvider ServiceProvider { get; private set; }
object ICollection.SyncRoot => this;
public TViewModel this[int index] public TViewModel this[int index]
{ {
get => collection[index]; get => collection[index];
@@ -374,7 +376,7 @@ public partial class ObservableCollectionViewModel<TViewModel> :
isInitialized = true; isInitialized = true;
await Mediator.PublishAsync<Enumerate<TViewModel>>(); await Publisher.PublishAsync<Enumerate<TViewModel>>();
await InitializeAsync(); await InitializeAsync();
} }
@@ -384,6 +386,7 @@ public partial class ObservableCollectionViewModel<TViewModel> :
public class ObservableCollectionViewModel(IServiceProvider serviceProvider, public class ObservableCollectionViewModel(IServiceProvider serviceProvider,
IServiceFactory serviceFactory, IServiceFactory serviceFactory,
IMediator mediator, IPublisher publisher,
ISubscriber subscriber,
IDisposer disposer) : IDisposer disposer) :
ObservableCollectionViewModel<IDisposable>(serviceProvider, serviceFactory, mediator, disposer); ObservableCollectionViewModel<IDisposable>(serviceProvider, serviceFactory, publisher, subscriber, disposer);
+2 -2
View File
@@ -6,7 +6,7 @@ namespace Hyperbar;
public class ObservableViewModel(IServiceProvider serviceProvider, public class ObservableViewModel(IServiceProvider serviceProvider,
IServiceFactory serviceFactory, IServiceFactory serviceFactory,
IMediator mediator, IPublisher publisher,
IDisposer disposer) : IDisposer disposer) :
ObservableObject, ObservableObject,
IObservableViewModel IObservableViewModel
@@ -18,7 +18,7 @@ public class ObservableViewModel(IServiceProvider serviceProvider,
public ICommand InitializeCommand => public ICommand InitializeCommand =>
new AsyncRelayCommand(CoreInitializeAsync); new AsyncRelayCommand(CoreInitializeAsync);
public IMediator Mediator => mediator; public IPublisher Publisher => publisher;
public IServiceFactory ServiceFactory => serviceFactory; public IServiceFactory ServiceFactory => serviceFactory;
-1
View File
@@ -3,5 +3,4 @@
public delegate Task<TResponse> HandlerDelegate<TMessage, TResponse>(TMessage message, public delegate Task<TResponse> HandlerDelegate<TMessage, TResponse>(TMessage message,
CancellationToken cancellationToken) CancellationToken cancellationToken)
where TMessage : where TMessage :
notnull,
IMessage; IMessage;
+15 -17
View File
@@ -1,27 +1,25 @@
namespace Hyperbar; namespace Hyperbar;
public class HandlerWrapper<TRequest, TResponse> public class HandlerWrapper<TMessage, TReply>(IHandler<TMessage, TReply> handler,
where TRequest : IEnumerable<IPipelineBehavior<TMessage, TReply>> pipelineBehaviours)
class, where TMessage : class, IRequest<TReply>
IRequest<TResponse>
{ {
private readonly HandlerDelegate<TRequest, TResponse> handler; private readonly IEnumerable<IPipelineBehavior<TMessage, TReply>> pipelineBehaviours =
pipelineBehaviours.Reverse();
public HandlerWrapper(IHandler<TRequest, TResponse> concreteHandler, public async Task<TReply> Handle(TMessage message, CancellationToken cancellationToken)
IEnumerable<IPipelineBehavior<TRequest, TResponse>> pipelineBehaviours)
{ {
HandlerDelegate<TRequest, TResponse> handler = concreteHandler.Handle; HandlerDelegate<TMessage, TReply> currentHandler = handler.Handle;
foreach (IPipelineBehavior<TRequest, TResponse>? pipeline in pipelineBehaviours.Reverse()) foreach (IPipelineBehavior<TMessage, TReply> behavior in pipelineBehaviours)
{ {
HandlerDelegate<TRequest, TResponse> handlerCopy = handler; HandlerDelegate<TMessage, TReply> previousHandler = currentHandler;
IPipelineBehavior<TRequest, TResponse> pipelineCopy = pipeline; currentHandler = async (msg, token) =>
{
handler = (TRequest message, CancellationToken cancellationToken) => return await behavior.Handle(msg, previousHandler, token);
pipelineCopy.Handle(message, handlerCopy, cancellationToken); };
} }
this.handler = handler; return await currentHandler(message, cancellationToken);
} }
public Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken) => handler(request, cancellationToken);
} }
-32
View File
@@ -2,41 +2,9 @@
public interface IMediator public interface IMediator
{ {
Task PublishAsync<TNotification>(TNotification notification,
object key,
CancellationToken cancellationToken = default)
where TNotification :
INotification;
Task PublishAsync<TNotification>(object key,
CancellationToken cancellationToken = default)
where TNotification :
INotification,
new();
Task PublishAsync<TNotification>(TNotification notification,
CancellationToken cancellationToken = default)
where TNotification :
INotification;
Task PublishAsync(object notification,
CancellationToken cancellationToken = default);
Task PublishAsync(object notification,
Func<Func<Task>, Task> marshal,
object? key = null,
CancellationToken cancellationToken = default);
Task PublishAsync<TNotification>(CancellationToken cancellationToken = default)
where TNotification :
INotification,
new();
Task<TResponse?> SendAsync<TResponse>(IRequest<TResponse> request, Task<TResponse?> SendAsync<TResponse>(IRequest<TResponse> request,
CancellationToken cancellationToken = default); CancellationToken cancellationToken = default);
Task<object?> SendAsync(object message, CancellationToken Task<object?> SendAsync(object message, CancellationToken
cancellationToken = default); cancellationToken = default);
void Subscribe(object handler);
} }
+2 -1
View File
@@ -1,3 +1,4 @@
namespace Hyperbar; namespace Hyperbar;
public interface INotification : IMessage; public interface INotification :
IMessage;
+34
View File
@@ -0,0 +1,34 @@
namespace Hyperbar;
public interface IPublisher
{
Task PublishAsync<TNotification>(TNotification notification,
object key,
CancellationToken cancellationToken = default)
where TNotification :
INotification;
Task PublishAsync<TNotification>(object key,
CancellationToken cancellationToken = default)
where TNotification :
INotification,
new();
Task PublishAsync<TNotification>(TNotification notification,
CancellationToken cancellationToken = default)
where TNotification :
INotification;
Task PublishAsync(object notification,
CancellationToken cancellationToken = default);
Task PublishAsync(object notification,
Func<Func<Task>, Task> marshal,
object? key = null,
CancellationToken cancellationToken = default);
Task PublishAsync<TNotification>(CancellationToken cancellationToken = default)
where TNotification :
INotification,
new();
}
+8
View File
@@ -0,0 +1,8 @@
namespace Hyperbar;
public interface ISubscriber
{
void Remove(object subscriber);
void Add(object subscriber);
}
@@ -0,0 +1,10 @@
namespace Hyperbar;
public interface ISubscriptionManager
{
IEnumerable<object?> GetHandlers(Type notificationType, object key);
void Remove(object subscriber);
void Add(object subscriber);
}
+2 -125
View File
@@ -1,91 +1,8 @@
using Microsoft.Extensions.DependencyInjection; namespace Hyperbar;
using System.Collections.Concurrent;
using System.Reflection;
namespace Hyperbar; public class Mediator(IServiceProvider provider) :
public class Mediator(IServiceProvider provider,
IDispatcher dispatcher) :
IMediator IMediator
{ {
private readonly ConcurrentDictionary<object, List<object>> handlers = [];
public Task PublishAsync<TNotification>(object key,
CancellationToken cancellationToken = default)
where TNotification :
INotification,
new() => PublishAsync(new TNotification(), args => dispatcher.InvokeAsync(async () => await args()),
key, cancellationToken);
public Task PublishAsync<TNotification>(TNotification notification,
CancellationToken cancellationToken = default)
where TNotification :
INotification
{
return PublishAsync(notification, args => dispatcher.InvokeAsync(async () => await args()),
null, cancellationToken);
}
public Task PublishAsync<TNotification>(TNotification notification,
object key,
CancellationToken cancellationToken = default)
where TNotification :
INotification
{
return PublishAsync(notification, args => dispatcher.InvokeAsync(async () => await args()),
key, cancellationToken);
}
public Task PublishAsync(object notification,
Func<Func<Task>, Task> marshal,
object? key = null,
CancellationToken cancellationToken = default)
{
Type notificationType = notification.GetType();
List<object?> handlers = provider.GetServices(typeof(INotificationHandler<>)
.MakeGenericType(notificationType)).ToList();
foreach (KeyValuePair<object, List<object>> subscriber in this.handlers)
{
if (subscriber.Key.Equals($"{key?.ToString()}:{notificationType}"))
{
handlers.AddRange(subscriber.Value);
}
}
foreach (object? handler in handlers)
{
if (handler is not null)
{
Type? handlerType = handler.GetType();
MethodInfo? handleMethod = handlerType.GetMethod("Handle",
[notificationType, typeof(CancellationToken)]);
if (handleMethod is not null)
{
marshal(() => (Task)handleMethod.Invoke(handler, new object[] { notification,
cancellationToken })!);
}
}
}
return Task.CompletedTask;
}
public Task PublishAsync<TNotification>(CancellationToken cancellationToken = default)
where TNotification :
INotification,
new() => PublishAsync(new TNotification(), args => dispatcher.InvokeAsync(async () => await args()),
null, cancellationToken);
public Task PublishAsync(object notification,
CancellationToken cancellationToken = default)
{
return PublishAsync(notification, args => dispatcher.InvokeAsync(async () => await args()),
null, cancellationToken);
}
public Task<TResponse?> SendAsync<TResponse>(IRequest<TResponse> request, public Task<TResponse?> SendAsync<TResponse>(IRequest<TResponse> request,
CancellationToken cancellationToken = default) CancellationToken cancellationToken = default)
{ {
@@ -121,44 +38,4 @@ public class Mediator(IServiceProvider provider,
return Task.FromResult<object?>(default); return Task.FromResult<object?>(default);
} }
public void Subscribe(object handler)
{
Type handlerType = handler.GetType();
object? key = GetKeyFromHandler(handlerType, handler);
foreach (Type interfaceType in GetNotificationHandlerInterfaces(handlerType))
{
if (interfaceType.GetGenericArguments().FirstOrDefault() is Type argumentType)
{
handlers.AddOrUpdate($"{(key is not null ? $"{key}:" : "")}{argumentType}", new List<object> { handler }, (value, collection) =>
{
collection.Add(handler);
return collection;
});
}
}
}
private object? GetKeyFromHandler(Type handlerType, object handler)
{
if (handlerType.GetCustomAttribute<NotificationHandlerAttribute>() is NotificationHandlerAttribute attribute)
{
if (handlerType.GetProperty($"{attribute.Key}") is PropertyInfo property
&& property.GetValue(handler) is { } value)
{
return value;
}
else
{
return attribute.Key;
}
}
return null;
}
private IEnumerable<Type> GetNotificationHandlerInterfaces(Type handlerType) => handlerType.GetInterfaces()
.Where(interfaceType => interfaceType.IsGenericType && interfaceType
.GetGenericTypeDefinition() == typeof(INotificationHandler<>));
} }
@@ -1,16 +0,0 @@
namespace Hyperbar;
public class NotficationRelayHandler<TFromNotification, ToNotification>(IMediator mediator) :
INotificationHandler<TFromNotification>,
IHandler
where TFromNotification :
INotification
where ToNotification :
INotification, new()
{
private readonly IMediator mediator = mediator;
public Task Handle(TFromNotification notification, CancellationToken cancellationToken) =>
mediator.PublishAsync<ToNotification>(cancellationToken);
}
+84
View File
@@ -0,0 +1,84 @@
using Microsoft.Extensions.DependencyInjection;
using System.Reflection;
namespace Hyperbar;
public class Publisher(ISubscriptionManager subscriptionManager,
IServiceProvider provider,
IDispatcher dispatcher) :
IPublisher
{
public Task PublishAsync<TNotification>(object key,
CancellationToken cancellationToken = default)
where TNotification :
INotification,
new() => PublishAsync(new TNotification(), args => dispatcher.InvokeAsync(async () => await args()),
key, cancellationToken);
public Task PublishAsync<TNotification>(TNotification notification,
CancellationToken cancellationToken = default)
where TNotification :
INotification
{
return PublishAsync(notification, args => dispatcher.InvokeAsync(async () => await args()),
null, cancellationToken);
}
public Task PublishAsync<TNotification>(TNotification notification,
object key,
CancellationToken cancellationToken = default)
where TNotification :
INotification
{
return PublishAsync(notification, args => dispatcher.InvokeAsync(async () => await args()),
key, cancellationToken);
}
public Task PublishAsync(object notification,
Func<Func<Task>, Task> marshal,
object? key = null,
CancellationToken cancellationToken = default)
{
Type notificationType = notification.GetType();
List<object?> handlers = provider.GetServices(typeof(INotificationHandler<>)
.MakeGenericType(notificationType)).ToList();
foreach (object? handler in subscriptionManager.GetHandlers(notificationType,
$"{key?.ToString()}:{notificationType}"))
{
handlers.Add(handler);
}
foreach (object? handler in handlers)
{
if (handler is not null)
{
Type? handlerType = handler.GetType();
MethodInfo? handleMethod = handlerType.GetMethod("Handle",
[notificationType, typeof(CancellationToken)]);
if (handleMethod is not null)
{
marshal(() => (Task)handleMethod.Invoke(handler, new object[] { notification,
cancellationToken })!);
}
}
}
return Task.CompletedTask;
}
public Task PublishAsync<TNotification>(CancellationToken cancellationToken = default)
where TNotification :
INotification,
new() => PublishAsync(new TNotification(), args => dispatcher.InvokeAsync(async () => await args()),
null, cancellationToken);
public Task PublishAsync(object notification,
CancellationToken cancellationToken = default)
{
return PublishAsync(notification, args => dispatcher.InvokeAsync(async () => await args()),
null, cancellationToken);
}
}
+11
View File
@@ -0,0 +1,11 @@
namespace Hyperbar;
public class Subscriber(ISubscriptionManager subscriptionManager) :
ISubscriber
{
public void Remove(object subscriber) =>
subscriptionManager.Remove(subscriber);
public void Add(object subscriber) =>
subscriptionManager.Add(subscriber);
}
+3
View File
@@ -0,0 +1,3 @@
namespace Hyperbar;
public record Subscription(object Handler);
+90
View File
@@ -0,0 +1,90 @@
using System.Collections.Concurrent;
using System.Reflection;
namespace Hyperbar;
public class SubscriptionManager :
ISubscriptionManager
{
private readonly ConcurrentDictionary<object, List<WeakReference>> subscriptions = new();
public IEnumerable<object?> GetHandlers(Type notificationType, object key)
{
if (subscriptions.TryGetValue($"{key?.ToString()}:{notificationType}",
out List<WeakReference>? subscribers))
{
foreach (WeakReference weakRef in subscribers.ToArray())
{
object? target = weakRef.Target;
if (target != null)
{
yield return target;
}
else
{
subscribers.Remove(weakRef);
}
}
}
}
public void Remove(object subscriber)
{
Type handlerType = subscriber.GetType();
object? key = GetKeyFromHandler(handlerType, subscriber);
foreach (Type interfaceType in GetHandlerInterfaces(handlerType))
{
if (interfaceType.GetGenericArguments().FirstOrDefault() is Type argumentType)
{
if (subscriptions.TryGetValue($"{(key is not null ? $"{key}:" : "")}{argumentType}", out List<WeakReference>? subscribers))
{
for (int i = subscribers.Count - 1; i >= 0; i--)
{
if (!subscribers[i].IsAlive || subscribers[i].Target == subscriber)
{
subscribers.RemoveAt(i);
}
}
}
}
}
}
public void Add(object subscriber)
{
Type handlerType = subscriber.GetType();
object? key = GetKeyFromHandler(handlerType, subscriber);
foreach (Type interfaceType in GetHandlerInterfaces(handlerType))
{
if (interfaceType.GetGenericArguments().FirstOrDefault() is Type argumentType)
{
subscriptions.AddOrUpdate($"{(key is not null ? $"{key}:" : "")}{argumentType}", _ => new List<WeakReference> { new WeakReference(subscriber) }, (_, collection) =>
{
collection.Add(new WeakReference(subscriber));
return collection;
});
}
}
}
private static object? GetKeyFromHandler(Type handlerType, object handler)
{
if (handlerType.GetCustomAttribute<NotificationHandlerAttribute>() is NotificationHandlerAttribute attribute)
{
if (handlerType.GetProperty($"{attribute.Key}") is PropertyInfo property
&& property.GetValue(handler) is { } value)
{
return value;
}
else
{
return attribute.Key;
}
}
return null;
}
private static IEnumerable<Type> GetHandlerInterfaces(Type handlerType) =>
handlerType.GetInterfaces().Where(interfaceType => interfaceType.IsGenericType &&
interfaceType.GetGenericTypeDefinition() == typeof(INotificationHandler<>));
}