Medistor reworked to handle ui threading in a cleaner way

This commit is contained in:
TheXamlGuy
2024-01-18 16:54:38 +00:00
parent 7dc125ebc7
commit a3065b25ee
19 changed files with 91 additions and 95 deletions
@@ -34,21 +34,21 @@ public class MediaController :
disposer.Dispose(this); disposer.Dispose(this);
} }
public async ValueTask Handle(Play notification, public async Task Handle(Play notification,
CancellationToken cancellationToken) => CancellationToken cancellationToken) =>
await session.TryPlayAsync(); await session.TryPlayAsync();
public async ValueTask Handle(Pause notification, public async Task Handle(Pause notification,
CancellationToken cancellationToken) => CancellationToken cancellationToken) =>
await session.TryPauseAsync(); await session.TryPauseAsync();
public async ValueTask Handle(Request<Playback> notification, public async Task Handle(Request<Playback> notification,
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
await mediator.PublishAsync(new Changed<Playback>(), cancellationToken); await mediator.PublishAsync(new Changed<Playback>(), cancellationToken);
} }
public async ValueTask Handle(Request<MediaInformation> _, public async Task Handle(Request<MediaInformation> _,
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
using (await asyncLock) using (await asyncLock)
@@ -7,13 +7,13 @@ public class MediaControllerHandler(IMediator mediator,
ICache<MediaController, MediaControllerViewModel> cache) : ICache<MediaController, MediaControllerViewModel> cache) :
INotificationHandler<Created<MediaController>> INotificationHandler<Created<MediaController>>
{ {
public async ValueTask 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)
{ {
if (scopeProvider.TryGet(mediaController, out IServiceScope? serviceScope)) if (scopeProvider.TryGet(mediaController, out IServiceScope? serviceScope))
{
if (serviceScope is not null) if (serviceScope is not null)
{ {
if (serviceScope.ServiceProvider.GetService<IFactory<MediaController, MediaControllerViewModel?>>() if (serviceScope.ServiceProvider.GetService<IFactory<MediaController, MediaControllerViewModel?>>()
@@ -29,6 +29,4 @@ public class MediaControllerHandler(IMediator mediator,
} }
} }
} }
}
} }
@@ -21,7 +21,7 @@ public partial class MediaInformationViewModel(IServiceFactory serviceFactory,
public ICommand Initialize => public ICommand Initialize =>
new AsyncRelayCommand(InitializeAsync); new AsyncRelayCommand(InitializeAsync);
public ValueTask Handle(Changed<MediaInformation> notification, public Task Handle(Changed<MediaInformation> notification,
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
if (notification.Value is MediaInformation value) if (notification.Value is MediaInformation value)
@@ -30,7 +30,7 @@ public partial class MediaInformationViewModel(IServiceFactory serviceFactory,
Description = value.Description; Description = value.Description;
} }
return ValueTask.CompletedTask; return Task.CompletedTask;
} }
public async Task InitializeAsync() => public async Task InitializeAsync() =>
@@ -6,7 +6,7 @@ public class PrimaryWidgetConfigurationHandler(IMediator mediator,
ICache<Guid, IWidgetComponentViewModel> cache) : ICache<Guid, IWidgetComponentViewModel> cache) :
INotificationHandler<ConfigurationChanged<PrimaryWidgetConfiguration>> INotificationHandler<ConfigurationChanged<PrimaryWidgetConfiguration>>
{ {
public async ValueTask Handle(ConfigurationChanged<PrimaryWidgetConfiguration> notification, public async Task Handle(ConfigurationChanged<PrimaryWidgetConfiguration> notification,
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
HashSet<Guid> configurationIds = new(configuration.SelectMany(item => new[] { item } HashSet<Guid> configurationIds = new(configuration.SelectMany(item => new[] { item }
@@ -23,10 +23,10 @@ public class PrimaryWidgetConfigurationHandler(IMediator mediator,
{ {
if (!cache.ContainsKey(item.Id)) if (!cache.ContainsKey(item.Id))
{ {
if (factory.Create(item) is IWidgetComponentViewModel value) if (factory.Create(item) is IWidgetComponentViewModel viewModel)
{ {
await mediator.PublishAsync(Inserted<IWidgetComponentViewModel> await mediator.PublishAsync(Inserted<IWidgetComponentViewModel>
.For<PrimaryWidgetViewModel>(item.Order, value), .For<PrimaryWidgetViewModel>(item.Order, viewModel),
cancellationToken); cancellationToken);
} }
} }
@@ -25,6 +25,7 @@ public class WidgetComponentViewModelFactory(IServiceFactory service,
if (processCommandConfiguration.Commands is { Count: > 0 } childCommandConfigurations) if (processCommandConfiguration.Commands is { Count: > 0 } childCommandConfigurations)
{ {
List<IWidgetComponentViewModel> childViewModels = []; List<IWidgetComponentViewModel> childViewModels = [];
foreach (PrimaryCommandConfiguration childCommandConfiguration in childCommandConfigurations) foreach (PrimaryCommandConfiguration childCommandConfiguration in childCommandConfigurations)
{ {
WidgetComponentViewModel? childViewModel = null; WidgetComponentViewModel? childViewModel = null;
@@ -6,9 +6,9 @@ public class AppConfigurationChangedHandler(DesktopBar desktopFlyout,
AppConfiguration configuration) : AppConfiguration configuration) :
INotificationHandler<ConfigurationChanged<AppConfiguration>> INotificationHandler<ConfigurationChanged<AppConfiguration>>
{ {
public ValueTask Handle(ConfigurationChanged<AppConfiguration> notification, CancellationToken cancellationToken) public Task Handle(ConfigurationChanged<AppConfiguration> notification, CancellationToken cancellationToken)
{ {
desktopFlyout.Placement = configuration.Placement; desktopFlyout.Placement = configuration.Placement;
return ValueTask.CompletedTask; return Task.CompletedTask;
} }
} }
@@ -3,12 +3,12 @@
namespace Hyperbar.Windows; namespace Hyperbar.Windows;
public class KeyAcceleratorHandler(IVirtualKeyboard virtualKeyboard) : public class KeyAcceleratorHandler(IVirtualKeyboard virtualKeyboard) :
IRequestHandler<KeyAccelerator> IHandler<KeyAccelerator>
{ {
public ValueTask<Unit> Handle(KeyAccelerator request, public Task<Unit> Handle(KeyAccelerator request,
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
virtualKeyboard.Send((int)request.Key, request.Modifiers?.Select(modifier => (int)modifier).ToArray() ?? []); virtualKeyboard.Send((int)request.Key, request.Modifiers?.Select(modifier => (int)modifier).ToArray() ?? []);
return default; return Task.FromResult<Unit>(default);
} }
} }
@@ -3,12 +3,12 @@
namespace Hyperbar.Windows; namespace Hyperbar.Windows;
public class StartProcessHandler : public class StartProcessHandler :
IRequestHandler<StartProcess> IHandler<StartProcess>
{ {
public ValueTask<Unit> Handle(StartProcess request, public Task<Unit> Handle(StartProcess request,
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
Process.Start(request.Process); Process.Start(request.Process);
return default; return Task.FromResult<Unit>(default);
} }
} }
@@ -138,9 +138,8 @@ public static class IServiceCollectionExtensions
{ {
Type notificationType = arguments[0]; Type notificationType = arguments[0];
services.TryAdd(new ServiceDescriptor(typeof(THandler), typeof(THandler), lifetime)); //services.TryAdd(new ServiceDescriptor(typeof(THandler), typeof(THandler), lifetime));
services.Add(new ServiceDescriptor(typeof(INotificationHandler<>).MakeGenericType(notificationType), services.Add(new ServiceDescriptor(typeof(INotificationHandler<>).MakeGenericType(notificationType), typeof(THandler), lifetime));
provider => provider.GetRequiredService<THandler>(), lifetime));
} }
} }
@@ -151,7 +150,7 @@ public static class IServiceCollectionExtensions
Type requestType = arguments[0]; Type requestType = arguments[0];
Type responseType = arguments[1]; Type responseType = arguments[1];
Type wrapperType = typeof(RequestClassHandlerWrapper<,>).MakeGenericType(requestType, responseType); Type wrapperType = typeof(HandlerWrapper<,>).MakeGenericType(requestType, responseType);
services.TryAdd(new ServiceDescriptor(typeof(THandler), typeof(THandler), lifetime)); services.TryAdd(new ServiceDescriptor(typeof(THandler), typeof(THandler), lifetime));
services.Add(new ServiceDescriptor(wrapperType, services.Add(new ServiceDescriptor(wrapperType,
@@ -169,14 +168,15 @@ public static class IServiceCollectionExtensions
return services; return services;
} }
public static IServiceCollection AddNotificationPipeline<TFromNotification, TToNotification>(this IServiceCollection services) //public static IServiceCollection AddNotificationPipeline<TFromNotification, TToNotification>(this IServiceCollection services)
where TFromNotification : // where TFromNotification :
INotification // INotification
where TToNotification : // where TToNotification :
INotification, new() // INotification, new()
{ //{
return services.AddHandler<NotficationPipelineHandler<TFromNotification, TToNotification>>(); // return services.AddHandler<NotficationPipelineHandler<TFromNotification, TToNotification>>();
} //}
public static IServiceCollection AddWidgetTemplate<TWidgetContent>(this IServiceCollection services) public static IServiceCollection AddWidgetTemplate<TWidgetContent>(this IServiceCollection services)
where TWidgetContent : where TWidgetContent :
IWidgetViewModel IWidgetViewModel
-1
View File
@@ -1,5 +1,4 @@
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
using System;
namespace Hyperbar; namespace Hyperbar;
@@ -1,6 +1,6 @@
namespace Hyperbar; namespace Hyperbar;
public delegate ValueTask<TResponse> MessageHandlerDelegate<TMessage, TResponse>(TMessage message, public delegate Task<TResponse> HandlerDelegate<TMessage, TResponse>(TMessage message,
CancellationToken cancellationToken) CancellationToken cancellationToken)
where TMessage : where TMessage :
notnull, notnull,
@@ -1,19 +1,19 @@
namespace Hyperbar; namespace Hyperbar;
public class RequestClassHandlerWrapper<TRequest, TResponse> public class HandlerWrapper<TRequest, TResponse>
where TRequest : where TRequest :
class, class,
IRequest<TResponse> IRequest<TResponse>
{ {
private readonly MessageHandlerDelegate<TRequest, TResponse> handler; private readonly HandlerDelegate<TRequest, TResponse> handler;
public RequestClassHandlerWrapper(IHandler<TRequest, TResponse> concreteHandler, public HandlerWrapper(IHandler<TRequest, TResponse> concreteHandler,
IEnumerable<IPipelineBehavior<TRequest, TResponse>> pipelineBehaviours) IEnumerable<IPipelineBehavior<TRequest, TResponse>> pipelineBehaviours)
{ {
MessageHandlerDelegate<TRequest, TResponse> handler = concreteHandler.Handle; HandlerDelegate<TRequest, TResponse> handler = concreteHandler.Handle;
foreach (IPipelineBehavior<TRequest, TResponse>? pipeline in pipelineBehaviours.Reverse()) foreach (IPipelineBehavior<TRequest, TResponse>? pipeline in pipelineBehaviours.Reverse())
{ {
MessageHandlerDelegate<TRequest, TResponse> handlerCopy = handler; HandlerDelegate<TRequest, TResponse> handlerCopy = handler;
IPipelineBehavior<TRequest, TResponse> pipelineCopy = pipeline; IPipelineBehavior<TRequest, TResponse> pipelineCopy = pipeline;
handler = (TRequest message, CancellationToken cancellationToken) => handler = (TRequest message, CancellationToken cancellationToken) =>
@@ -23,5 +23,5 @@ public class RequestClassHandlerWrapper<TRequest, TResponse>
this.handler = handler; this.handler = handler;
} }
public ValueTask<TResponse> Handle(TRequest request, CancellationToken cancellationToken) => handler(request, cancellationToken); public Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken) => handler(request, cancellationToken);
} }
+3 -5
View File
@@ -7,13 +7,11 @@ public interface IHandler<in TRequest, TResponse> :
where TRequest : where TRequest :
IRequest<TResponse> IRequest<TResponse>
{ {
ValueTask<TResponse> Handle(TRequest request, Task<TResponse> Handle(TRequest request,
CancellationToken cancellationToken); CancellationToken cancellationToken);
} }
public interface IRequestHandler<in TRequest> : public interface IHandler<in TRequest> :
IHandler<TRequest, Unit> IHandler<TRequest, Unit>
where TRequest : where TRequest :
IRequest<Unit> IRequest<Unit>;
{
}
+11 -5
View File
@@ -2,21 +2,27 @@
public interface IMediator public interface IMediator
{ {
ValueTask PublishAsync<TNotification>(TNotification notification, Task PublishAsync<TNotification>(TNotification notification,
CancellationToken cancellationToken = default) CancellationToken cancellationToken = default)
where TNotification : where TNotification :
INotification; INotification;
ValueTask PublishAsync<TNotification>(CancellationToken cancellationToken = default) Task PublishAsync<TNotification>(TNotification notification,
Func<Func<Task>, Task> marshal,
CancellationToken cancellationToken = default)
where TNotification :
INotification;
Task PublishAsync<TNotification>(CancellationToken cancellationToken = default)
where TNotification : where TNotification :
INotification, INotification,
new(); new();
ValueTask<TResponse> SendAsync<TResponse>(IRequest<TResponse> request, Task<TResponse?> SendAsync<TResponse>(IRequest<TResponse> request,
CancellationToken cancellationToken = default); CancellationToken cancellationToken = default);
ValueTask<object?> SendAsync(object message, CancellationToken Task<object?> SendAsync(object message, CancellationToken
cancellationToken = default); cancellationToken = default);
void Subscribe(object subscriber); void Subscribe(object handler);
} }
+1 -1
View File
@@ -5,6 +5,6 @@ public interface INotificationHandler<in TNotification> :
where TNotification : where TNotification :
INotification INotification
{ {
ValueTask Handle(TNotification notification, Task Handle(TNotification notification,
CancellationToken cancellationToken); CancellationToken cancellationToken);
} }
+2 -2
View File
@@ -5,7 +5,7 @@ public interface IPipelineBehavior<TMessage, TResponse>
notnull, notnull,
IMessage IMessage
{ {
ValueTask<TResponse> Handle(TMessage message, Task<TResponse> Handle(TMessage message,
MessageHandlerDelegate<TMessage, TResponse> next, HandlerDelegate<TMessage, TResponse> next,
CancellationToken cancellationToken = default); CancellationToken cancellationToken = default);
} }
+26 -17
View File
@@ -7,11 +7,18 @@ public class Mediator(IServiceProvider provider,
IDispatcher dispatcher) : IDispatcher dispatcher) :
IMediator IMediator
{ {
private readonly SynchronizationContext? context = SynchronizationContext.Current;
private readonly ConcurrentDictionary<Type, List<dynamic>> subjects = []; private readonly ConcurrentDictionary<Type, List<dynamic>> subjects = [];
public async ValueTask PublishAsync<TNotification>(TNotification notification, public Task PublishAsync<TNotification>(TNotification notification,
CancellationToken cancellationToken = default)
where TNotification :
INotification
{
return PublishAsync(notification, args => dispatcher.InvokeAsync(async () => await args()), cancellationToken);
}
public Task PublishAsync<TNotification>(TNotification notification,
Func<Func<Task>, Task> marshal,
CancellationToken cancellationToken = default) CancellationToken cancellationToken = default)
where TNotification : where TNotification :
INotification INotification
@@ -32,19 +39,21 @@ public class Mediator(IServiceProvider provider,
foreach (INotificationHandler<TNotification> handler in handlers) foreach (INotificationHandler<TNotification> handler in handlers)
{ {
await dispatcher.InvokeAsync(async () => await handler.Handle(notification, cancellationToken)); marshal(() => handler.Handle(notification, cancellationToken));
}
} }
public ValueTask PublishAsync<TNotification>(CancellationToken cancellationToken = default) return Task.CompletedTask;
}
public Task PublishAsync<TNotification>(CancellationToken cancellationToken = default)
where TNotification : where TNotification :
INotification, INotification,
new() => PublishAsync(new TNotification(), cancellationToken); new() => PublishAsync(new TNotification(), null, cancellationToken);
public ValueTask<TResponse> SendAsync<TResponse>(IRequest<TResponse> request, public Task<TResponse?> SendAsync<TResponse>(IRequest<TResponse> request,
CancellationToken cancellationToken = default) CancellationToken cancellationToken = default)
{ {
dynamic? handler = provider.GetService(typeof(RequestClassHandlerWrapper<,>) dynamic? handler = provider.GetService(typeof(HandlerWrapper<,>)
.MakeGenericType(request.GetType(), typeof(TResponse))); .MakeGenericType(request.GetType(), typeof(TResponse)));
if (handler is not null) if (handler is not null)
@@ -52,10 +61,10 @@ public class Mediator(IServiceProvider provider,
return handler.Handle((dynamic)request, cancellationToken); return handler.Handle((dynamic)request, cancellationToken);
} }
return default; return Task.FromResult<TResponse?>(default);
} }
public ValueTask<object?> SendAsync(object message, public Task<object?> SendAsync(object message,
CancellationToken cancellationToken = default) CancellationToken cancellationToken = default)
{ {
if (message.GetType().GetInterface(typeof(IRequest<>).Name) is { } requestType) if (message.GetType().GetInterface(typeof(IRequest<>).Name) is { } requestType)
@@ -64,7 +73,7 @@ public class Mediator(IServiceProvider provider,
{ {
Type responseType = arguments[0]; Type responseType = arguments[0];
dynamic? handler = provider.GetService(typeof(RequestClassHandlerWrapper<,>) dynamic? handler = provider.GetService(typeof(HandlerWrapper<,>)
.MakeGenericType(message.GetType(), responseType)); .MakeGenericType(message.GetType(), responseType));
if (handler is not null) if (handler is not null)
@@ -74,12 +83,12 @@ public class Mediator(IServiceProvider provider,
} }
} }
return default; return Task.FromResult<object?>(default);
} }
public void Subscribe(object subject) public void Subscribe(object handler)
{ {
Type[] interfaceTypes = subject.GetType().GetInterfaces(); Type[] interfaceTypes = handler.GetType().GetInterfaces();
foreach (Type interfaceType in interfaceTypes.Where(x => x.IsGenericType)) foreach (Type interfaceType in interfaceTypes.Where(x => x.IsGenericType))
{ {
if (interfaceType.GetGenericTypeDefinition() == typeof(INotificationHandler<>)) if (interfaceType.GetGenericTypeDefinition() == typeof(INotificationHandler<>))
@@ -87,9 +96,9 @@ public class Mediator(IServiceProvider provider,
if (interfaceType.GetGenericArguments() is { Length: 1 } arguments) if (interfaceType.GetGenericArguments() is { Length: 1 } arguments)
{ {
Type notificationType = arguments[0]; Type notificationType = arguments[0];
subjects.AddOrUpdate(notificationType, [subject], (value, collection) => subjects.AddOrUpdate(notificationType, [handler], (value, collection) =>
{ {
collection.Add(subject); collection.Add(handler);
return collection; return collection;
}); });
} }
@@ -1,15 +0,0 @@
namespace Hyperbar;
public class NotficationPipelineHandler<TFromNotification, ToNotification>(IMediator mediator) :
INotificationHandler<TFromNotification>,
IHandler
where TFromNotification :
INotification
where ToNotification :
INotification, new()
{
private readonly IMediator mediator = mediator;
public ValueTask Handle(TFromNotification notification, CancellationToken cancellationToken) =>
mediator.PublishAsync(new ToNotification(), cancellationToken);
}
@@ -206,7 +206,7 @@ public partial class ObservableCollectionViewModel<TItem> :
IEnumerator IEnumerable.GetEnumerator() => IEnumerator IEnumerable.GetEnumerator() =>
((IEnumerable)collection).GetEnumerator(); ((IEnumerable)collection).GetEnumerator();
public ValueTask Handle(Removed<TItem> notification, public Task Handle(Removed<TItem> notification,
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
foreach (TItem item in this.ToList()) foreach (TItem item in this.ToList())
@@ -223,10 +223,10 @@ public partial class ObservableCollectionViewModel<TItem> :
} }
} }
return ValueTask.CompletedTask; return Task.CompletedTask;
} }
public ValueTask Handle(Created<TItem> notification, public Task Handle(Created<TItem> notification,
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
if (notification.Target.Equals(GetType().Name)) if (notification.Target.Equals(GetType().Name))
@@ -237,10 +237,10 @@ public partial class ObservableCollectionViewModel<TItem> :
} }
} }
return ValueTask.CompletedTask; return Task.CompletedTask;
} }
public ValueTask Handle(Inserted<TItem> notification, public Task Handle(Inserted<TItem> notification,
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
if (notification.Target.Equals(GetType().Name)) if (notification.Target.Equals(GetType().Name))
@@ -251,7 +251,7 @@ public partial class ObservableCollectionViewModel<TItem> :
} }
} }
return ValueTask.CompletedTask; return Task.CompletedTask;
} }
public int IndexOf(TItem item) => public int IndexOf(TItem item) =>