wip
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
namespace Toolkit.Foundation;
|
namespace Toolkit.Foundation;
|
||||||
|
|
||||||
public class AggerateAttribute(object key,
|
public class AggerateAttribute(Type type, object key,
|
||||||
AggerateMode mode = AggerateMode.Reset) : NotificationAttribute(key)
|
AggerateMode mode = AggerateMode.Reset) : NotificationAttribute(type, key)
|
||||||
{
|
{
|
||||||
public AggerateMode Mode => mode;
|
public AggerateMode Mode => mode;
|
||||||
}
|
}
|
||||||
@@ -13,7 +13,7 @@ public class AppService(IEnumerable<IInitializer> initializers,
|
|||||||
await initializer.Initialize();
|
await initializer.Initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
publisher.Publish<StartedEventArgs>(cancellationToken);
|
publisher.Publish<StartedEventArgs>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
|
public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ public class HandlerProvider(SubscriptionCollection subscriptions) :
|
|||||||
object? key = null)
|
object? key = null)
|
||||||
{
|
{
|
||||||
string subscriptionKey = $"{(key is not null ? $"{key}:" : "")}{type}";
|
string subscriptionKey = $"{(key is not null ? $"{key}:" : "")}{type}";
|
||||||
var d = subscriptions;
|
|
||||||
if (subscriptions.TryGetValue(subscriptionKey, out List<WeakReference>? subscribers))
|
if (subscriptions.TryGetValue(subscriptionKey, out List<WeakReference>? subscribers))
|
||||||
{
|
{
|
||||||
foreach (WeakReference weakRef in subscribers.ToArray())
|
foreach (WeakReference weakRef in subscribers.ToArray())
|
||||||
|
|||||||
@@ -32,7 +32,15 @@ public static class IServiceCollectionExtensions
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static IServiceCollection AddHandler<THandler>(this IServiceCollection services,
|
public static IServiceCollection AddHandler<THandler>(this IServiceCollection services,
|
||||||
ServiceLifetime lifetime = ServiceLifetime.Transient)
|
string key)
|
||||||
|
where THandler : IHandler
|
||||||
|
{
|
||||||
|
return AddHandler<THandler>(services, ServiceLifetime.Transient, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IServiceCollection AddHandler<THandler>(this IServiceCollection services,
|
||||||
|
ServiceLifetime lifetime = ServiceLifetime.Transient,
|
||||||
|
string? key = null)
|
||||||
where THandler : IHandler
|
where THandler : IHandler
|
||||||
{
|
{
|
||||||
if (typeof(THandler).GetInterfaces() is Type[] contracts)
|
if (typeof(THandler).GetInterfaces() is Type[] contracts)
|
||||||
@@ -47,14 +55,34 @@ public static class IServiceCollectionExtensions
|
|||||||
Type wrapperType = typeof(NotificationHandlerWrapper<>)
|
Type wrapperType = typeof(NotificationHandlerWrapper<>)
|
||||||
.MakeGenericType(notificationType);
|
.MakeGenericType(notificationType);
|
||||||
|
|
||||||
services.TryAdd(new ServiceDescriptor(typeof(INotificationHandler<>)
|
if (key is not null)
|
||||||
.MakeGenericType(notificationType), typeof(THandler), lifetime));
|
{
|
||||||
|
services.TryAdd(new ServiceDescriptor(typeof(INotificationHandler<>)
|
||||||
|
.MakeGenericType(notificationType), key, typeof(THandler), lifetime));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
services.TryAdd(new ServiceDescriptor(typeof(INotificationHandler<>)
|
||||||
|
.MakeGenericType(notificationType), typeof(THandler), lifetime));
|
||||||
|
}
|
||||||
|
|
||||||
services.Add(new ServiceDescriptor(wrapperType, provider =>
|
|
||||||
provider.GetService<IServiceFactory>()?.Create(wrapperType,
|
if (key is not null)
|
||||||
provider.GetRequiredService(typeof(INotificationHandler<>).MakeGenericType(notificationType)),
|
{
|
||||||
provider.GetServices(typeof(IPipelineBehaviour<>)
|
services.Add(new ServiceDescriptor(wrapperType, key, (provider, key) =>
|
||||||
.MakeGenericType(notificationType)))!, lifetime));
|
provider.GetService<IServiceFactory>()?.Create(wrapperType,
|
||||||
|
provider.GetRequiredKeyedService(typeof(INotificationHandler<>).MakeGenericType(notificationType), key),
|
||||||
|
provider.GetServices(typeof(IPipelineBehaviour<>)
|
||||||
|
.MakeGenericType(notificationType)))!, lifetime));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
services.Add(new ServiceDescriptor(wrapperType, provider =>
|
||||||
|
provider.GetService<IServiceFactory>()?.Create(wrapperType,
|
||||||
|
provider.GetRequiredService(typeof(INotificationHandler<>).MakeGenericType(notificationType)),
|
||||||
|
provider.GetServices(typeof(IPipelineBehaviour<>)
|
||||||
|
.MakeGenericType(notificationType)))!, lifetime));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (contract.Name == typeof(IHandler<,>).Name &&
|
if (contract.Name == typeof(IHandler<,>).Name &&
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
namespace Toolkit.Foundation;
|
namespace Toolkit.Foundation;
|
||||||
|
|
||||||
[AttributeUsage(AttributeTargets.Class, Inherited = true)]
|
|
||||||
public class NotificationAttribute(object key) : Attribute
|
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)]
|
||||||
|
public class NotificationAttribute(Type type, object key) : Attribute
|
||||||
{
|
{
|
||||||
|
public Type Type => type;
|
||||||
|
|
||||||
public object Key => key;
|
public object Key => key;
|
||||||
}
|
}
|
||||||
@@ -22,11 +22,23 @@ public static class ObjectExtensions
|
|||||||
where TAttribute : Attribute
|
where TAttribute : Attribute
|
||||||
{
|
{
|
||||||
Type type = obj.GetType();
|
Type type = obj.GetType();
|
||||||
if (type.GetAttribute<TAttribute>() is TAttribute attribute)
|
if (type.GetCustomAttribute<TAttribute>(true) is TAttribute attribute)
|
||||||
{
|
{
|
||||||
return attribute;
|
return attribute;
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static IEnumerable<TAttribute> GetAttributes<TAttribute>(this object obj)
|
||||||
|
where TAttribute : Attribute
|
||||||
|
{
|
||||||
|
Type type = obj.GetType();
|
||||||
|
if (type.GetCustomAttributes<TAttribute>(true) is IEnumerable<TAttribute> attributes)
|
||||||
|
{
|
||||||
|
return attributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Enumerable.Empty<TAttribute>();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -157,6 +157,8 @@ public partial class ObservableCollection<TItem> :
|
|||||||
{
|
{
|
||||||
int index = collection.Count;
|
int index = collection.Count;
|
||||||
InsertItem(index, item);
|
InsertItem(index, item);
|
||||||
|
|
||||||
|
UpdateSelection(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Add(object item)
|
public void Add(object item)
|
||||||
@@ -399,12 +401,17 @@ public partial class ObservableCollection<TItem> :
|
|||||||
{
|
{
|
||||||
T? item = Factory.Create<T>(parameters);
|
T? item = Factory.Create<T>(parameters);
|
||||||
InsertItem(index, item);
|
InsertItem(index, item);
|
||||||
|
UpdateSelection(item);
|
||||||
|
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Insert(int index, TItem item) =>
|
public void Insert(int index,
|
||||||
|
TItem item)
|
||||||
|
{
|
||||||
InsertItem(index, item);
|
InsertItem(index, item);
|
||||||
|
UpdateSelection(item);
|
||||||
|
}
|
||||||
|
|
||||||
void IList.Insert(int index,
|
void IList.Insert(int index,
|
||||||
object? value)
|
object? value)
|
||||||
@@ -412,6 +419,7 @@ public partial class ObservableCollection<TItem> :
|
|||||||
if (value is TItem item)
|
if (value is TItem item)
|
||||||
{
|
{
|
||||||
Insert(index, item);
|
Insert(index, item);
|
||||||
|
UpdateSelection(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -424,8 +432,27 @@ public partial class ObservableCollection<TItem> :
|
|||||||
|
|
||||||
TItem item = this[oldIndex];
|
TItem item = this[oldIndex];
|
||||||
|
|
||||||
|
bool moveSelection = false;
|
||||||
|
if (item is ISelectable oldSelection)
|
||||||
|
{
|
||||||
|
if (oldSelection.Selected)
|
||||||
|
{
|
||||||
|
moveSelection = true;
|
||||||
|
SelectedItem = default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
RemoveItem(oldIndex);
|
RemoveItem(oldIndex);
|
||||||
Insert(newIndex, item);
|
InsertItem(newIndex, item);
|
||||||
|
|
||||||
|
if (moveSelection)
|
||||||
|
{
|
||||||
|
if (item is ISelectable newSelection)
|
||||||
|
{
|
||||||
|
newSelection.Selected = true;
|
||||||
|
dispatcher.Invoke(() => SelectedItem = item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -535,7 +562,6 @@ public partial class ObservableCollection<TItem> :
|
|||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
UpdateSelection(item);
|
|
||||||
collection.Insert(index > Count ? Count : index, item);
|
collection.Insert(index > Count ? Count : index, item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,9 @@ public class Publisher(IHandlerProvider handlerProvider,
|
|||||||
Type handlerType = typeof(NotificationHandlerWrapper<>)
|
Type handlerType = typeof(NotificationHandlerWrapper<>)
|
||||||
.MakeGenericType(notificationType);
|
.MakeGenericType(notificationType);
|
||||||
|
|
||||||
List<object?> handlers = serviceProvider.GetServices(handlerType).ToList();
|
List<object?> handlers = key is not null ? serviceProvider.GetKeyedServices(handlerType, key).ToList() :
|
||||||
|
serviceProvider.GetServices(handlerType).ToList();
|
||||||
|
|
||||||
foreach (object? handler in handlerProvider.Get(notificationType, key))
|
foreach (object? handler in handlerProvider.Get(notificationType, key))
|
||||||
{
|
{
|
||||||
handlers.Add(handler);
|
handlers.Add(handler);
|
||||||
|
|||||||
@@ -9,11 +9,14 @@ public class Subscription(SubscriptionCollection subscriptions,
|
|||||||
public void Add(object subscriber)
|
public void Add(object subscriber)
|
||||||
{
|
{
|
||||||
Type handlerType = subscriber.GetType();
|
Type handlerType = subscriber.GetType();
|
||||||
object? key = GetKeyFromHandler(subscriber);
|
|
||||||
|
IDictionary<Type, object> keys = GetKeysFromHandler(subscriber);
|
||||||
foreach (Type interfaceType in GetHandlerInterfaces(handlerType))
|
foreach (Type interfaceType in GetHandlerInterfaces(handlerType))
|
||||||
{
|
{
|
||||||
if (interfaceType.GetGenericArguments().FirstOrDefault() is Type argumentType)
|
if (interfaceType.GetGenericArguments().FirstOrDefault() is Type argumentType)
|
||||||
{
|
{
|
||||||
|
keys.TryGetValue(argumentType, out object? key);
|
||||||
|
|
||||||
string subscriptionKey = $"{(key is not null ? $"{key}:" : "")}{argumentType}";
|
string subscriptionKey = $"{(key is not null ? $"{key}:" : "")}{argumentType}";
|
||||||
subscriptions.AddOrUpdate(subscriptionKey, _ => new List<WeakReference> { new(subscriber) }, (_, collection) =>
|
subscriptions.AddOrUpdate(subscriptionKey, _ => new List<WeakReference> { new(subscriber) }, (_, collection) =>
|
||||||
{
|
{
|
||||||
@@ -29,11 +32,13 @@ public class Subscription(SubscriptionCollection subscriptions,
|
|||||||
public void Remove(object subscriber)
|
public void Remove(object subscriber)
|
||||||
{
|
{
|
||||||
Type handlerType = subscriber.GetType();
|
Type handlerType = subscriber.GetType();
|
||||||
object? key = GetKeyFromHandler(subscriber);
|
IDictionary<Type, object> keys = GetKeysFromHandler(subscriber);
|
||||||
foreach (Type interfaceType in GetHandlerInterfaces(handlerType))
|
foreach (Type interfaceType in GetHandlerInterfaces(handlerType))
|
||||||
{
|
{
|
||||||
if (interfaceType.GetGenericArguments().FirstOrDefault() is Type argumentType)
|
if (interfaceType.GetGenericArguments().FirstOrDefault() is Type argumentType)
|
||||||
{
|
{
|
||||||
|
keys.TryGetValue(argumentType, out object? key);
|
||||||
|
|
||||||
string subscriptionKey = $"{(key is not null ? $"{key}:" : "")}{argumentType}";
|
string subscriptionKey = $"{(key is not null ? $"{key}:" : "")}{argumentType}";
|
||||||
if (subscriptions.TryGetValue(subscriptionKey, out List<WeakReference>? subscribers))
|
if (subscriptions.TryGetValue(subscriptionKey, out List<WeakReference>? subscribers))
|
||||||
{
|
{
|
||||||
@@ -69,9 +74,22 @@ public class Subscription(SubscriptionCollection subscriptions,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private object? GetKeyFromHandler(object handler) =>
|
//private object? GetKeyFromHandler(object handler) =>
|
||||||
handler.GetAttribute<NotificationAttribute>() is NotificationAttribute attribute
|
// handler.GetAttribute<NotificationAttribute>() is NotificationAttribute attribute
|
||||||
? handler.GetPropertyValue(() => attribute.Key) is { } value ? value : attribute.Key : null;
|
// ? handler.GetPropertyValue(() => attribute.Key) is { } value ? value : attribute.Key : null;
|
||||||
|
|
||||||
|
private IDictionary<Type, object> GetKeysFromHandler(object handler)
|
||||||
|
{
|
||||||
|
Dictionary<Type, object> keys = [];
|
||||||
|
|
||||||
|
foreach (NotificationAttribute attribute in handler.GetAttributes<NotificationAttribute>())
|
||||||
|
{
|
||||||
|
keys.Add(attribute.Type, attribute.Key);
|
||||||
|
}
|
||||||
|
|
||||||
|
return keys;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private IEnumerable<Type> GetHandlerInterfaces(Type handlerType) =>
|
private IEnumerable<Type> GetHandlerInterfaces(Type handlerType) =>
|
||||||
handlerType.GetInterfaces().Where(interfaceType =>
|
handlerType.GetInterfaces().Where(interfaceType =>
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
using System.Reflection;
|
|
||||||
|
|
||||||
namespace Toolkit.Foundation;
|
|
||||||
|
|
||||||
public static class TypeExtensions
|
|
||||||
{
|
|
||||||
public static TAttribute? GetAttribute<TAttribute>(this Type type)
|
|
||||||
where TAttribute : Attribute
|
|
||||||
{
|
|
||||||
if (type.GetCustomAttribute<TAttribute>() is TAttribute attribute)
|
|
||||||
{
|
|
||||||
return attribute;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user