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