Added messaging pipeline
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Hyperbar.Options;
|
||||
namespace Hyperbar;
|
||||
|
||||
public class ConfigurationWriter<TConfiguration>(string path,
|
||||
string section,
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
|
||||
namespace Hyperbar.Options
|
||||
{
|
||||
public interface IConfigurationWriter<TConfiguration>
|
||||
where TConfiguration :
|
||||
class, new()
|
||||
{
|
||||
void Write(Action<TConfiguration> updateDelegate);
|
||||
namespace Hyperbar;
|
||||
|
||||
void Write(TConfiguration value);
|
||||
}
|
||||
public interface IConfigurationWriter<TConfiguration>
|
||||
where TConfiguration :
|
||||
class, new()
|
||||
{
|
||||
void Write(Action<TConfiguration> updateDelegate);
|
||||
|
||||
void Write(TConfiguration value);
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
using Hyperbar.Options;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Hyperbar;
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
using Hyperbar.Lifecycles;
|
||||
using Hyperbar.Options;
|
||||
using Hyperbar.Templates;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.FileProviders;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
@@ -67,11 +64,11 @@ public static class IServiceCollectionExtensions
|
||||
string key = contentType.Name;
|
||||
|
||||
services.AddTransient(typeof(IWidgetViewModel), contentType);
|
||||
services.TryAddTransient(provider => provider.GetService<IWidgetView>()!);
|
||||
services.TryAddTransient(templateType, provider => provider.GetService<IWidgetView>()!);
|
||||
|
||||
services.AddKeyedTransient(typeof(IWidgetViewModel), key, contentType);
|
||||
services.TryAddKeyedTransient(templateType, key);
|
||||
|
||||
services.TryAddKeyedTransient<IWidgetView>(key, (provider, key) => provider.GetService<IWidgetView>()!);
|
||||
|
||||
services.AddTransient<IContentTemplateDescriptor>(provider => new ContentTemplateDescriptor
|
||||
{
|
||||
ContentType = contentType,
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace Hyperbar;
|
||||
|
||||
public interface IServiceFactory
|
||||
{
|
||||
TService Create<TService>(params object?[] parameters);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace Hyperbar;
|
||||
|
||||
public class ServiceFactory(Func<Type, object?[], object> factory) :
|
||||
IServiceFactory
|
||||
{
|
||||
public TService Create<TService>(params object?[] parameters) =>
|
||||
(TService)factory(typeof(TService), parameters);
|
||||
}
|
||||
@@ -5,6 +5,7 @@
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using Microsoft.Extensions.Hosting;
|
||||
|
||||
namespace Hyperbar.Lifecycles;
|
||||
namespace Hyperbar;
|
||||
|
||||
public class AppService(IEnumerable<IInitializer> initializers) :
|
||||
IHostedService
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace Hyperbar.Lifecycles;
|
||||
namespace Hyperbar;
|
||||
|
||||
public interface IInitializer
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Hyperbar.Lifecycles;
|
||||
namespace Hyperbar;
|
||||
|
||||
public interface IWidgetBuilder
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace Hyperbar.Lifecycles;
|
||||
namespace Hyperbar;
|
||||
|
||||
public interface IWidgetContext
|
||||
{
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
namespace Hyperbar.Lifecycles;
|
||||
|
||||
public class ObservableCollectionViewModel<TItem> :
|
||||
ObservableCollection<TItem>
|
||||
{
|
||||
public void AddRange(IEnumerable<TItem> collection)
|
||||
{
|
||||
foreach (TItem? item in collection)
|
||||
{
|
||||
Add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class ObservableCollectionViewModel :
|
||||
ObservableCollectionViewModel<object>
|
||||
{
|
||||
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
namespace Hyperbar.Lifecycles;
|
||||
|
||||
public class WidgetButtonViewModel
|
||||
{
|
||||
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace Hyperbar.Lifecycles;
|
||||
namespace Hyperbar;
|
||||
|
||||
public class WidgetContext(IServiceProvider serviceProvider) :
|
||||
IWidgetContext
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
using Hyperbar.Templates;
|
||||
|
||||
namespace Hyperbar.Lifecycles;
|
||||
|
||||
public class WidgetViewModelBase(ITemplateFactory templateFactory) :
|
||||
ObservableCollectionViewModel<IWidgetComponentViewModel>,
|
||||
IWidgetViewModel,
|
||||
ITemplatedViewModel
|
||||
{
|
||||
public ITemplateFactory TemplateFactory { get; } = templateFactory;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
namespace Hyperbar;
|
||||
|
||||
public class CommandClassHandlerWrapper<TRequest, TResponse>
|
||||
where TRequest :
|
||||
class,
|
||||
ICommand<TResponse>
|
||||
{
|
||||
private readonly MessageHandlerDelegate<TRequest, TResponse> handler;
|
||||
|
||||
public CommandClassHandlerWrapper(ICommandHandler<TRequest, TResponse> concreteHandler,
|
||||
IEnumerable<IPipelineBehavior<TRequest, TResponse>> pipelineBehaviours)
|
||||
{
|
||||
MessageHandlerDelegate<TRequest, TResponse> handler = concreteHandler.Handle;
|
||||
|
||||
foreach (IPipelineBehavior<TRequest, TResponse>? pipeline in pipelineBehaviours.Reverse())
|
||||
{
|
||||
MessageHandlerDelegate<TRequest, TResponse> handlerCopy = handler;
|
||||
IPipelineBehavior<TRequest, TResponse> pipelineCopy = pipeline;
|
||||
handler = (TRequest message, CancellationToken cancellationToken) =>
|
||||
pipelineCopy.Handle(message, handlerCopy, cancellationToken);
|
||||
}
|
||||
|
||||
this.handler = handler;
|
||||
}
|
||||
|
||||
public ValueTask<TResponse> Handle(TRequest request, CancellationToken cancellationToken) => handler(request, cancellationToken);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace Hyperbar;
|
||||
|
||||
public interface ICommand : ICommand<Unit>;
|
||||
|
||||
public interface ICommand<out TResponse> : IMessage;
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
namespace Hyperbar;
|
||||
|
||||
public interface ICommandHandler<in TCommand> : ICommandHandler<TCommand, Unit>
|
||||
where TCommand :
|
||||
ICommand<Unit>;
|
||||
|
||||
public interface ICommandHandler<in TCommand, TResponse>
|
||||
where TCommand :
|
||||
ICommand<TResponse>
|
||||
{
|
||||
ValueTask<TResponse> Handle(TCommand command,
|
||||
CancellationToken cancellationToken);
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
namespace Hyperbar;
|
||||
|
||||
public interface IMediator
|
||||
{
|
||||
ValueTask Publish<TNotification>(TNotification notification,
|
||||
CancellationToken cancellationToken = default)
|
||||
where TNotification :
|
||||
INotification;
|
||||
|
||||
ValueTask<TResponse> Send<TResponse>(IRequest<TResponse> request,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
ValueTask<TResponse> Send<TResponse>(ICommand<TResponse> command,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
ValueTask<TResponse> Send<TResponse>(IQuery<TResponse> query,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
ValueTask<object?> Send(object message, CancellationToken
|
||||
cancellationToken = default);
|
||||
|
||||
void Subscribe(object subscriber);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
namespace Hyperbar;
|
||||
|
||||
public interface IMessage;
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
namespace Hyperbar;
|
||||
|
||||
public interface INotification : IMessage;
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace Hyperbar;
|
||||
|
||||
public interface INotificationHandler<in TNotification>
|
||||
where TNotification :
|
||||
INotification
|
||||
{
|
||||
ValueTask Handle(TNotification notification,
|
||||
CancellationToken cancellationToken);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
namespace Hyperbar;
|
||||
|
||||
public interface IPipelineBehavior<TMessage, TResponse>
|
||||
where TMessage :
|
||||
notnull,
|
||||
IMessage
|
||||
{
|
||||
ValueTask<TResponse> Handle(TMessage message,
|
||||
MessageHandlerDelegate<TMessage, TResponse> next,
|
||||
CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
namespace Hyperbar;
|
||||
|
||||
public interface IQuery<out TResponse> : IMessage;
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace Hyperbar;
|
||||
|
||||
public interface IQueryHandler<in TQuery, TResponse>
|
||||
where TQuery :
|
||||
IQuery<TResponse>
|
||||
{
|
||||
ValueTask<TResponse> Handle(TQuery query,
|
||||
CancellationToken cancellationToken);
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
namespace Hyperbar;
|
||||
|
||||
public interface IRequest<out TResponse> : IMessage;
|
||||
|
||||
public interface IRequest : IRequest<Unit>;
|
||||
@@ -0,0 +1,17 @@
|
||||
namespace Hyperbar;
|
||||
|
||||
public interface IRequestHandler<in TRequest, TResponse>
|
||||
where TRequest :
|
||||
IRequest<TResponse>
|
||||
{
|
||||
ValueTask<TResponse> Handle(TRequest request,
|
||||
CancellationToken cancellationToken);
|
||||
}
|
||||
|
||||
public interface IRequestHandler<in TRequest> :
|
||||
IRequestHandler<TRequest, Unit>
|
||||
where TRequest :
|
||||
IRequest<Unit>
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Hyperbar;
|
||||
|
||||
public class Mediator(IServiceProvider provider) :
|
||||
IMediator
|
||||
{
|
||||
private readonly ConditionalWeakTable<Type, dynamic> handlers = [];
|
||||
|
||||
public ValueTask Publish<TNotification>(TNotification notification,
|
||||
CancellationToken cancellationToken = default)
|
||||
where TNotification :
|
||||
INotification
|
||||
{
|
||||
List<INotificationHandler<TNotification>> handlers =
|
||||
provider.GetServices<INotificationHandler<TNotification>>().ToList();
|
||||
|
||||
foreach (KeyValuePair<Type, dynamic> handler in this.handlers)
|
||||
{
|
||||
if (handler.Key == typeof(TNotification))
|
||||
{
|
||||
handlers.Add(handler.Value);
|
||||
}
|
||||
}
|
||||
|
||||
if (handlers.Count == 0)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
else if (handlers.Count == 1)
|
||||
{
|
||||
return handlers[0].Handle(notification, cancellationToken);
|
||||
}
|
||||
|
||||
return default;
|
||||
}
|
||||
|
||||
public ValueTask<TResponse> Send<TResponse>(IRequest<TResponse> request,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
dynamic? handler = provider.GetService(typeof(RequestClassHandlerWrapper<,>)
|
||||
.MakeGenericType(request.GetType(), typeof(TResponse)));
|
||||
|
||||
if (handler is not null)
|
||||
{
|
||||
return handler.Handle((dynamic)request, cancellationToken);
|
||||
}
|
||||
|
||||
return default;
|
||||
}
|
||||
|
||||
public ValueTask<TResponse> Send<TResponse>(ICommand<TResponse> command,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
dynamic? handler = provider.GetService(typeof(CommandClassHandlerWrapper<,>)
|
||||
.MakeGenericType(command.GetType(), typeof(TResponse)));
|
||||
|
||||
if (handler is not null)
|
||||
{
|
||||
return handler.Handle((dynamic)command, cancellationToken);
|
||||
}
|
||||
|
||||
return default;
|
||||
}
|
||||
|
||||
public ValueTask<TResponse> Send<TResponse>(IQuery<TResponse> query,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
dynamic? handler = provider.GetService(typeof(QueryClassHandlerWrapper<,>)
|
||||
.MakeGenericType(query.GetType(), typeof(TResponse)));
|
||||
|
||||
if (handler is not null)
|
||||
{
|
||||
return handler.Handle((dynamic)query, cancellationToken);
|
||||
}
|
||||
|
||||
return default;
|
||||
}
|
||||
|
||||
public ValueTask<object?> Send(object message,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (message.GetType().GetInterface(typeof(IRequest<>).Name) is { } requestType)
|
||||
{
|
||||
if (requestType.GetGenericArguments() is { Length: 1 } arguments)
|
||||
{
|
||||
Type responseType = arguments[0];
|
||||
|
||||
dynamic? handler = provider.GetService(typeof(RequestClassHandlerWrapper<,>)
|
||||
.MakeGenericType(message.GetType(), responseType));
|
||||
|
||||
if (handler is not null)
|
||||
{
|
||||
return handler.Handle((dynamic)message, cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (message.GetType().GetInterface(typeof(ICommand<>).Name) is { } commandType)
|
||||
{
|
||||
if (commandType.GetGenericArguments() is { Length: 1 } arguments)
|
||||
{
|
||||
Type responseType = arguments[0];
|
||||
|
||||
dynamic? handler = provider.GetService(typeof(CommandClassHandlerWrapper<,>)
|
||||
.MakeGenericType(message.GetType(), responseType));
|
||||
|
||||
if (handler is not null)
|
||||
{
|
||||
return handler.Handle((dynamic)message, cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (message.GetType().GetInterface(typeof(IQuery<>).Name) is { } queryType)
|
||||
{
|
||||
if (queryType.GetGenericArguments() is { Length: 1 } arguments)
|
||||
{
|
||||
Type responseType = arguments[0];
|
||||
|
||||
dynamic? handler = provider.GetService(typeof(QueryClassHandlerWrapper<,>)
|
||||
.MakeGenericType(message.GetType(), responseType));
|
||||
if (handler is not null)
|
||||
{
|
||||
return handler.Handle((dynamic)message, cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return default;
|
||||
}
|
||||
|
||||
public void Subscribe(object subject)
|
||||
{
|
||||
Type[] interfaceTypes = subject.GetType().GetInterfaces();
|
||||
foreach (Type interfaceType in interfaceTypes.Where(x => x.IsGenericType))
|
||||
{
|
||||
if (interfaceType.GetGenericTypeDefinition() == typeof(INotificationHandler<>))
|
||||
{
|
||||
if (interfaceType.GetGenericArguments() is { Length: 1 } arguments)
|
||||
{
|
||||
Type notificationType = arguments[0];
|
||||
handlers.Add(notificationType, subject);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace Hyperbar;
|
||||
|
||||
public delegate ValueTask<TResponse> MessageHandlerDelegate<TMessage, TResponse>(TMessage message,
|
||||
CancellationToken cancellationToken)
|
||||
where TMessage :
|
||||
notnull,
|
||||
IMessage;
|
||||
@@ -0,0 +1,28 @@
|
||||
namespace Hyperbar;
|
||||
|
||||
public class QueryClassHandlerWrapper<TRequest, TResponse>
|
||||
where TRequest :
|
||||
class,
|
||||
IQuery<TResponse>
|
||||
{
|
||||
private readonly MessageHandlerDelegate<TRequest, TResponse> handler;
|
||||
|
||||
public QueryClassHandlerWrapper(IQueryHandler<TRequest, TResponse> concreteHandler,
|
||||
IEnumerable<IPipelineBehavior<TRequest, TResponse>> pipelineBehaviours)
|
||||
{
|
||||
MessageHandlerDelegate<TRequest, TResponse> handler = concreteHandler.Handle;
|
||||
|
||||
foreach (IPipelineBehavior<TRequest, TResponse>? pipeline in pipelineBehaviours.Reverse())
|
||||
{
|
||||
MessageHandlerDelegate<TRequest, TResponse> handlerCopy = handler;
|
||||
IPipelineBehavior<TRequest, TResponse> pipelineCopy = pipeline;
|
||||
handler = (TRequest message, CancellationToken cancellationToken) =>
|
||||
pipelineCopy.Handle(message, handlerCopy, cancellationToken);
|
||||
}
|
||||
|
||||
this.handler = handler;
|
||||
}
|
||||
|
||||
public ValueTask<TResponse> Handle(TRequest request, CancellationToken cancellationToken) =>
|
||||
handler(request, cancellationToken);
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
namespace Hyperbar;
|
||||
|
||||
public class RequestClassHandlerWrapper<TRequest, TResponse>
|
||||
where TRequest :
|
||||
class,
|
||||
IRequest<TResponse>
|
||||
{
|
||||
private readonly MessageHandlerDelegate<TRequest, TResponse> handler;
|
||||
|
||||
public RequestClassHandlerWrapper(IRequestHandler<TRequest, TResponse> concreteHandler,
|
||||
IEnumerable<IPipelineBehavior<TRequest, TResponse>> pipelineBehaviours)
|
||||
{
|
||||
MessageHandlerDelegate<TRequest, TResponse> handler = concreteHandler.Handle;
|
||||
foreach (IPipelineBehavior<TRequest, TResponse>? pipeline in pipelineBehaviours.Reverse())
|
||||
{
|
||||
MessageHandlerDelegate<TRequest, TResponse> handlerCopy = handler;
|
||||
IPipelineBehavior<TRequest, TResponse> pipelineCopy = pipeline;
|
||||
|
||||
handler = (TRequest message, CancellationToken cancellationToken) =>
|
||||
pipelineCopy.Handle(message, handlerCopy, cancellationToken);
|
||||
}
|
||||
|
||||
this.handler = handler;
|
||||
}
|
||||
|
||||
public ValueTask<TResponse> Handle(TRequest request, CancellationToken cancellationToken) => handler(request, cancellationToken);
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
namespace Hyperbar;
|
||||
|
||||
public readonly struct Unit :
|
||||
IEquatable<Unit>,
|
||||
IComparable<Unit>,
|
||||
IComparable
|
||||
{
|
||||
private static readonly Unit value = new();
|
||||
|
||||
public static ref readonly Unit Value => ref value;
|
||||
|
||||
public static ValueTask<Unit> ValueTask => new(value);
|
||||
|
||||
public int CompareTo(Unit other) => 0;
|
||||
|
||||
int IComparable.CompareTo(object? obj) => 0;
|
||||
|
||||
public override int GetHashCode() => 0;
|
||||
|
||||
public bool Equals(Unit other) => true;
|
||||
|
||||
public override bool Equals(object? obj) => obj is Unit;
|
||||
|
||||
public static bool operator ==(Unit _, Unit __) => true;
|
||||
|
||||
public static bool operator !=(Unit _, Unit __) => false;
|
||||
|
||||
public override string ToString() => "()";
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace Hyperbar.Templates;
|
||||
namespace Hyperbar;
|
||||
|
||||
public record ContentTemplateDescriptor :
|
||||
IContentTemplateDescriptor
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace Hyperbar.Templates;
|
||||
namespace Hyperbar;
|
||||
|
||||
public interface IContentTemplateDescriptor
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace Hyperbar.Templates;
|
||||
namespace Hyperbar;
|
||||
|
||||
public interface ITemplateFactory
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace Hyperbar.Templates;
|
||||
namespace Hyperbar;
|
||||
|
||||
public interface ITemplatedViewModel
|
||||
{
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
namespace Hyperbar.Lifecycles;
|
||||
namespace Hyperbar;
|
||||
|
||||
public interface IWidgetComponentViewModel
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace Hyperbar.Lifecycles;
|
||||
namespace Hyperbar;
|
||||
|
||||
public interface IWidgetViewModel
|
||||
{
|
||||
@@ -0,0 +1,48 @@
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
namespace Hyperbar;
|
||||
|
||||
public class ObservableCollectionViewModel<TItem>(IServiceFactory serviceFactory) :
|
||||
ObservableCollection<TItem>
|
||||
{
|
||||
public TItem Add()
|
||||
{
|
||||
TItem? item = serviceFactory.Create<TItem>();
|
||||
|
||||
Add(item);
|
||||
return item;
|
||||
}
|
||||
|
||||
public TItem Add<T>(params object?[] parameters)
|
||||
where T : TItem
|
||||
{
|
||||
T? item = serviceFactory.Create<T>(parameters);
|
||||
Add(item);
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
public TItem Add<T>()
|
||||
where T :
|
||||
TItem
|
||||
{
|
||||
T? item = serviceFactory.Create<T>();
|
||||
Add(item);
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
public void AddRange(IEnumerable<TItem> items)
|
||||
{
|
||||
foreach (TItem? item in items)
|
||||
{
|
||||
Add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class ObservableCollectionViewModel(IServiceFactory serviceFactory) :
|
||||
ObservableCollectionViewModel<object>(serviceFactory)
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
|
||||
namespace Hyperbar;
|
||||
|
||||
public partial class WidgetButtonViewModel :
|
||||
WidgetComponentViewModelBase
|
||||
{
|
||||
[ObservableProperty]
|
||||
private string? icon;
|
||||
|
||||
[ObservableProperty]
|
||||
private IRelayCommand? click;
|
||||
|
||||
public WidgetButtonViewModel(ITemplateFactory templateFactory,
|
||||
string? icon = null,
|
||||
Action? action = null) : base(templateFactory)
|
||||
{
|
||||
this.icon = icon;
|
||||
if (action is not null)
|
||||
{
|
||||
click = new RelayCommand(action);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
|
||||
namespace Hyperbar;
|
||||
|
||||
public partial class WidgetComponentViewModelBase(ITemplateFactory templateFactory) :
|
||||
ObservableObject,
|
||||
IWidgetComponentViewModel,
|
||||
ITemplatedViewModel
|
||||
{
|
||||
public ITemplateFactory TemplateFactory => templateFactory;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace Hyperbar;
|
||||
|
||||
public class WidgetViewModelBase(ITemplateFactory templateFactory,
|
||||
IServiceFactory serviceFactory) :
|
||||
ObservableCollectionViewModel<IWidgetComponentViewModel>(serviceFactory),
|
||||
IWidgetViewModel,
|
||||
ITemplatedViewModel
|
||||
{
|
||||
public ITemplateFactory TemplateFactory => templateFactory;
|
||||
}
|
||||
Reference in New Issue
Block a user