add keyed based publication to mediator
This commit is contained in:
@@ -1,7 +1,25 @@
|
||||
namespace Hyperbar;
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class NotificationHandlerAttribute(object key) : Attribute
|
||||
{
|
||||
public object Key { get; } = key;
|
||||
}
|
||||
|
||||
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 :
|
||||
@@ -9,6 +27,7 @@ public interface IMediator
|
||||
|
||||
Task PublishAsync<TNotification>(TNotification notification,
|
||||
Func<Func<Task>, Task> marshal,
|
||||
object? key = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
where TNotification :
|
||||
INotification;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Hyperbar;
|
||||
|
||||
@@ -7,18 +8,37 @@ public class Mediator(IServiceProvider provider,
|
||||
IDispatcher dispatcher) :
|
||||
IMediator
|
||||
{
|
||||
private readonly ConcurrentDictionary<Type, List<dynamic>> subjects = [];
|
||||
private readonly ConcurrentDictionary<object, List<dynamic>> subjects = [];
|
||||
|
||||
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()), cancellationToken);
|
||||
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<TNotification>(TNotification notification,
|
||||
Func<Func<Task>, Task> marshal,
|
||||
object? key = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
where TNotification :
|
||||
INotification
|
||||
@@ -26,14 +46,11 @@ public class Mediator(IServiceProvider provider,
|
||||
List<INotificationHandler<TNotification>> handlers =
|
||||
provider.GetServices<INotificationHandler<TNotification>>().ToList();
|
||||
|
||||
foreach (KeyValuePair<Type, List<dynamic>> handler in subjects)
|
||||
foreach (KeyValuePair<object, List<dynamic>> handler in subjects)
|
||||
{
|
||||
if (handler.Key == typeof(TNotification))
|
||||
if (key is not null && handler.Key.Equals(key) || handler.Key.Equals(typeof(TNotification)))
|
||||
{
|
||||
foreach (dynamic value in handler.Value)
|
||||
{
|
||||
handlers.Add(value);
|
||||
}
|
||||
handlers.Add(handler.Value[0]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,7 +65,8 @@ public class Mediator(IServiceProvider provider,
|
||||
public Task PublishAsync<TNotification>(CancellationToken cancellationToken = default)
|
||||
where TNotification :
|
||||
INotification,
|
||||
new() => PublishAsync(new TNotification(), null, cancellationToken);
|
||||
new() => PublishAsync(new TNotification(), args => dispatcher.InvokeAsync(async () => await args()),
|
||||
null, cancellationToken);
|
||||
|
||||
public Task<TResponse?> SendAsync<TResponse>(IRequest<TResponse> request,
|
||||
CancellationToken cancellationToken = default)
|
||||
@@ -88,21 +106,37 @@ public class Mediator(IServiceProvider provider,
|
||||
|
||||
public void Subscribe(object handler)
|
||||
{
|
||||
Type[] interfaceTypes = handler.GetType().GetInterfaces();
|
||||
foreach (Type interfaceType in interfaceTypes.Where(x => x.IsGenericType))
|
||||
Type handlerType = handler.GetType();
|
||||
object? key = null;
|
||||
|
||||
if (Attribute.GetCustomAttribute(handlerType, typeof(NotificationHandlerAttribute))
|
||||
is NotificationHandlerAttribute attribute)
|
||||
{
|
||||
if (interfaceType.GetGenericTypeDefinition() == typeof(INotificationHandler<>))
|
||||
if (handlerType.GetProperty($"{attribute.Key}") is PropertyInfo property)
|
||||
{
|
||||
if (interfaceType.GetGenericArguments() is { Length: 1 } arguments)
|
||||
if (property.GetValue(handler, null) is { } value)
|
||||
{
|
||||
Type notificationType = arguments[0];
|
||||
subjects.AddOrUpdate(notificationType, [handler], (value, collection) =>
|
||||
{
|
||||
collection.Add(handler);
|
||||
return collection;
|
||||
});
|
||||
key = value;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
key = attribute.Key;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (Type interfaceType in handlerType.GetInterfaces().Where(x => x.IsGenericType
|
||||
&& x.GetGenericTypeDefinition() == typeof(INotificationHandler<>)))
|
||||
{
|
||||
if (interfaceType.GetGenericArguments() is { Length: 1 } arguments)
|
||||
{
|
||||
key ??= arguments[0];
|
||||
subjects.AddOrUpdate(key, [handler], (value, collection) =>
|
||||
{
|
||||
collection.Add(handler);
|
||||
return collection;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,3 @@
|
||||
namespace Hyperbar;
|
||||
|
||||
public record Inserted<TValue>(int Index, TValue Value, object Target) : INotification
|
||||
{
|
||||
public static Inserted<TValue> For<TTarget>(int index, TValue value)
|
||||
{
|
||||
return new Inserted<TValue>(index, value, typeof(TTarget).Name);
|
||||
}
|
||||
}
|
||||
public record Inserted<TValue>(int Index, TValue Value) : INotification;
|
||||
@@ -229,12 +229,9 @@ public partial class ObservableCollectionViewModel<TItem> :
|
||||
public Task Handle(Created<TItem> notification,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
if (notification.Target.Equals(GetType().Name))
|
||||
if (notification.Value is TItem item)
|
||||
{
|
||||
if (notification.Value is TItem item)
|
||||
{
|
||||
Add(item);
|
||||
}
|
||||
Add(item);
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
@@ -243,12 +240,9 @@ public partial class ObservableCollectionViewModel<TItem> :
|
||||
public Task Handle(Inserted<TItem> notification,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
if (notification.Target.Equals(GetType().Name))
|
||||
if (notification.Value is TItem item)
|
||||
{
|
||||
if (notification.Value is TItem item)
|
||||
{
|
||||
Insert(notification.Index, item);
|
||||
}
|
||||
Insert(notification.Index, item);
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
|
||||
@@ -3,14 +3,15 @@ using CommunityToolkit.Mvvm.Input;
|
||||
|
||||
namespace Hyperbar;
|
||||
|
||||
[NotificationHandler(nameof(Id))]
|
||||
public partial class WidgetButtonViewModel(IServiceFactory serviceFactory,
|
||||
IMediator mediator,
|
||||
IDisposer disposer,
|
||||
ITemplateFactory templateFactory,
|
||||
Guid guid = default,
|
||||
Guid id,
|
||||
string? text = null,
|
||||
string? icon = null,
|
||||
RelayCommand? command = null) : WidgetComponentViewModel(serviceFactory, mediator, disposer, templateFactory, guid)
|
||||
RelayCommand? command = null) : WidgetComponentViewModel(serviceFactory, mediator, disposer, templateFactory)
|
||||
{
|
||||
[ObservableProperty]
|
||||
private IRelayCommand? click = command;
|
||||
@@ -18,6 +19,9 @@ public partial class WidgetButtonViewModel(IServiceFactory serviceFactory,
|
||||
[ObservableProperty]
|
||||
private string? icon = icon;
|
||||
|
||||
[ObservableProperty]
|
||||
private Guid id = id;
|
||||
|
||||
[ObservableProperty]
|
||||
private string? text = text;
|
||||
}
|
||||
@@ -7,29 +7,20 @@ public partial class WidgetComponentViewModel :
|
||||
IWidgetComponentViewModel,
|
||||
ITemplatedViewModel
|
||||
{
|
||||
[ObservableProperty]
|
||||
private Guid id;
|
||||
|
||||
public WidgetComponentViewModel(IServiceFactory serviceFactory,
|
||||
IMediator mediator,
|
||||
IDisposer disposer,
|
||||
ITemplateFactory templateFactory,
|
||||
IEnumerable<IWidgetComponentViewModel> items,
|
||||
Guid id = default) : base(serviceFactory, mediator, disposer, items)
|
||||
IEnumerable<IWidgetComponentViewModel> items) : base(serviceFactory, mediator, disposer, items)
|
||||
{
|
||||
this.id = id;
|
||||
|
||||
TemplateFactory = templateFactory;
|
||||
}
|
||||
|
||||
public WidgetComponentViewModel(IServiceFactory serviceFactory,
|
||||
IMediator mediator,
|
||||
IDisposer disposer,
|
||||
ITemplateFactory templateFactory,
|
||||
Guid id = default) : base(serviceFactory, mediator, disposer)
|
||||
ITemplateFactory templateFactory) : base(serviceFactory, mediator, disposer)
|
||||
{
|
||||
this.id = id;
|
||||
|
||||
TemplateFactory = templateFactory;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,14 +3,15 @@ using CommunityToolkit.Mvvm.Input;
|
||||
|
||||
namespace Hyperbar;
|
||||
|
||||
[NotificationHandler(nameof(Id))]
|
||||
public partial class WidgetMenuViewModel(IServiceFactory serviceFactory,
|
||||
IMediator mediator,
|
||||
IDisposer disposer,
|
||||
ITemplateFactory templateFactory,
|
||||
Guid guid = default,
|
||||
Guid id = default,
|
||||
string? text = null,
|
||||
string? icon = null,
|
||||
RelayCommand? command = null) : WidgetComponentViewModel(serviceFactory, mediator, disposer, templateFactory, guid)
|
||||
RelayCommand? command = null) : WidgetComponentViewModel(serviceFactory, mediator, disposer, templateFactory)
|
||||
{
|
||||
[ObservableProperty]
|
||||
private IRelayCommand? click = command;
|
||||
@@ -18,6 +19,9 @@ public partial class WidgetMenuViewModel(IServiceFactory serviceFactory,
|
||||
[ObservableProperty]
|
||||
private string? icon = icon;
|
||||
|
||||
[ObservableProperty]
|
||||
private Guid id = id;
|
||||
|
||||
[ObservableProperty]
|
||||
private string? text = text;
|
||||
}
|
||||
@@ -3,15 +3,16 @@ using CommunityToolkit.Mvvm.Input;
|
||||
|
||||
namespace Hyperbar;
|
||||
|
||||
[NotificationHandler(nameof(Id))]
|
||||
public partial class WidgetSplitButtonViewModel(IServiceFactory serviceFactory,
|
||||
IMediator mediator,
|
||||
IDisposer disposer,
|
||||
ITemplateFactory templateFactory,
|
||||
IEnumerable<IWidgetComponentViewModel> items,
|
||||
Guid guid = default,
|
||||
Guid id = default,
|
||||
string? text = null,
|
||||
string? icon = null,
|
||||
RelayCommand? command = null) : WidgetComponentViewModel(serviceFactory, mediator, disposer, templateFactory, items, guid)
|
||||
RelayCommand? command = null) : WidgetComponentViewModel(serviceFactory, mediator, disposer, templateFactory, items)
|
||||
{
|
||||
[ObservableProperty]
|
||||
private IRelayCommand? click = command;
|
||||
@@ -19,6 +20,9 @@ public partial class WidgetSplitButtonViewModel(IServiceFactory serviceFactory,
|
||||
[ObservableProperty]
|
||||
private string? icon = icon;
|
||||
|
||||
[ObservableProperty]
|
||||
private Guid id = id;
|
||||
|
||||
[ObservableProperty]
|
||||
private string? text = text;
|
||||
}
|
||||
Reference in New Issue
Block a user