Initial navigaiton work; opening Windows
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
using Microsoft.UI.Xaml;
|
||||
|
||||
namespace Hyperbar.UI.Windows;
|
||||
|
||||
public class WindowHandler :
|
||||
INavigationHandler<Window>
|
||||
{
|
||||
public Task Handle(Navigate<Window> args,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
if (args.Template is Window window)
|
||||
{
|
||||
window.Activate();
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
@@ -9,8 +9,8 @@ public class WidgetExtensionEnumerator(IFactory<Type, IWidget> factory,
|
||||
IMediator mediator) :
|
||||
INotificationHandler<Enumerate<WidgetExtension>>
|
||||
{
|
||||
public Task Handle(Enumerate<WidgetExtension> notification,
|
||||
CancellationToken cancellationToken)
|
||||
public Task Handle(Enumerate<WidgetExtension> args,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
string extensionsDirectory = Path.Combine(hostEnvironment.ContentRootPath, "Extensions");
|
||||
if (Directory.Exists(extensionsDirectory))
|
||||
|
||||
@@ -8,7 +8,6 @@ using Microsoft.UI.Dispatching;
|
||||
using Microsoft.UI.Xaml;
|
||||
using System.Reflection;
|
||||
using Hyperbar.Widget.Windows;
|
||||
using Microsoft.UI.Xaml.Markup;
|
||||
|
||||
namespace Hyperbar.Windows;
|
||||
|
||||
@@ -46,6 +45,8 @@ public partial class App :
|
||||
args.Placement = DesktopApplicationBarPlacemenet.Top;
|
||||
});
|
||||
|
||||
services.AddNavigationHandler<WindowHandler>();
|
||||
|
||||
services.AddSingleton<DesktopApplicationBar>();
|
||||
services.AddContentTemplate<ApplicationBarViewModel, ApplicationBarView>();
|
||||
services.AddContentTemplate<PrimaryViewModel, PrimaryView>();
|
||||
|
||||
@@ -15,9 +15,9 @@ public partial class SecondaryViewModel :
|
||||
IMediator mediator,
|
||||
IDisposer disposer,
|
||||
int index) : base(serviceFactory, mediator, disposer)
|
||||
{
|
||||
{
|
||||
TemplateFactory = templateFactory;
|
||||
this.index = index;
|
||||
this.TemplateFactory = templateFactory;
|
||||
|
||||
Add<SettingsButtonViewModel>();
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
Width="{ThemeResource ButtonWidth}"
|
||||
Height="{ThemeResource ButtonHeight}"
|
||||
Padding="{ThemeResource ButtonPadding}"
|
||||
Command="{x:Bind ViewModel.InvokeCommand}"
|
||||
Content=""
|
||||
FontFamily="{ThemeResource SymbolThemeFontFamily}"
|
||||
FontSize="16" />
|
||||
|
||||
@@ -2,9 +2,12 @@ using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace Hyperbar.Windows;
|
||||
|
||||
public sealed partial class SettingsButtonView :
|
||||
public partial class SettingsButtonView :
|
||||
UserControl
|
||||
{
|
||||
public SettingsButtonView() =>
|
||||
this.InitializeComponent();
|
||||
InitializeComponent();
|
||||
|
||||
protected SettingsButtonViewModel ViewModel =>
|
||||
(SettingsButtonViewModel)DataContext;
|
||||
}
|
||||
|
||||
@@ -1,11 +1,24 @@
|
||||
namespace Hyperbar.Windows;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
|
||||
public class SettingsButtonViewModel(ITemplateFactory templateFactory,
|
||||
IServiceFactory serviceFactory,
|
||||
IMediator mediator,
|
||||
IDisposer disposer) :
|
||||
ObservableViewModel(serviceFactory, mediator, disposer),
|
||||
namespace Hyperbar.Windows;
|
||||
|
||||
public partial class SettingsButtonViewModel :
|
||||
ObservableViewModel,
|
||||
ITemplatedViewModel
|
||||
{
|
||||
public ITemplateFactory TemplateFactory => templateFactory;
|
||||
[ObservableProperty]
|
||||
private IRelayCommand? invokeCommand;
|
||||
|
||||
public SettingsButtonViewModel(ITemplateFactory templateFactory,
|
||||
IServiceFactory serviceFactory,
|
||||
IMediator mediator,
|
||||
IDisposer disposer) : base(serviceFactory, mediator, disposer)
|
||||
{
|
||||
TemplateFactory = templateFactory;
|
||||
InvokeCommand = new AsyncRelayCommand(async () =>
|
||||
await mediator.PublishAsync(new Navigate("Settings")));
|
||||
}
|
||||
|
||||
public ITemplateFactory TemplateFactory { get; }
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<UserControl
|
||||
<Window
|
||||
x:Class="Hyperbar.Windows.SettingsView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<Grid />
|
||||
</UserControl>
|
||||
<Button>afsdfdg</Button>
|
||||
</Window>
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace Hyperbar.Windows
|
||||
{
|
||||
public sealed partial class SettingsView :
|
||||
UserControl
|
||||
public sealed partial class SettingsView :
|
||||
Window
|
||||
{
|
||||
public SettingsView() =>
|
||||
InitializeComponent();
|
||||
|
||||
@@ -3,6 +3,8 @@ using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.FileProviders;
|
||||
using Microsoft.Extensions.FileProviders.Physical;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Net.Mime;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace Hyperbar;
|
||||
@@ -128,6 +130,26 @@ public static class IServiceCollectionExtensions
|
||||
return services;
|
||||
}
|
||||
|
||||
public static IServiceCollection AddNavigationHandler<THandler>(this IServiceCollection services)
|
||||
where THandler :
|
||||
INavigationHandler,
|
||||
IHandler
|
||||
{
|
||||
Type? contract = typeof(THandler).GetInterfaces()
|
||||
.FirstOrDefault(t => t.Name == typeof(INavigationHandler<>).Name);
|
||||
|
||||
if (contract?.GetGenericArguments() is { Length: 1 } arguments)
|
||||
{
|
||||
services.AddTransient<INavigationDescriptor>(provider => new NavigationDescriptor
|
||||
{
|
||||
Type = arguments[0]
|
||||
});
|
||||
}
|
||||
|
||||
services.AddHandler<THandler>();
|
||||
return services;
|
||||
}
|
||||
|
||||
public static IServiceCollection AddContentTemplate<TContent, TTemplate>(this IServiceCollection services,
|
||||
object? key = null)
|
||||
{
|
||||
@@ -163,52 +185,59 @@ public static class IServiceCollectionExtensions
|
||||
|
||||
services.AddSingleton<IDisposer, Disposer>();
|
||||
|
||||
services.AddHandler<NavigateHandler>();
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
public static IServiceCollection AddHandler<THandler>(this IServiceCollection services,
|
||||
public static IServiceCollection AddHandler<THandler>(
|
||||
this IServiceCollection services,
|
||||
ServiceLifetime lifetime = ServiceLifetime.Transient)
|
||||
where THandler :
|
||||
IHandler
|
||||
where THandler : IHandler
|
||||
{
|
||||
if (typeof(THandler).GetInterfaces() is { } contracts)
|
||||
{
|
||||
foreach (Type contract in contracts)
|
||||
{
|
||||
if (contract.Name == typeof(INotificationHandler<>).Name)
|
||||
if (contract.Name == typeof(INotificationHandler<>).Name &&
|
||||
contract.GetGenericArguments() is { Length: 1 } notificationArguments)
|
||||
{
|
||||
if (contract.GetGenericArguments() is { Length: 1 } arguments)
|
||||
{
|
||||
Type notificationType = arguments[0];
|
||||
services.Add(new ServiceDescriptor(typeof(INotificationHandler<>).MakeGenericType(notificationType), typeof(THandler), lifetime));
|
||||
}
|
||||
Type notificationType = notificationArguments[0];
|
||||
services.Add(new ServiceDescriptor(
|
||||
typeof(INotificationHandler<>).MakeGenericType(notificationType),
|
||||
typeof(THandler),
|
||||
lifetime));
|
||||
}
|
||||
|
||||
if (contract.Name == typeof(IHandler<,>).Name)
|
||||
if (contract.Name == typeof(IHandler<,>).Name &&
|
||||
contract.GetGenericArguments() is { Length: 2 } handlerArguments)
|
||||
{
|
||||
if (contract.GetGenericArguments() is { Length: 2 } arguments)
|
||||
{
|
||||
Type requestType = arguments[0];
|
||||
Type responseType = arguments[1];
|
||||
Type requestType = handlerArguments[0];
|
||||
Type responseType = handlerArguments[1];
|
||||
|
||||
Type wrapperType = typeof(HandlerWrapper<,>).MakeGenericType(requestType, responseType);
|
||||
Type wrapperType = typeof(HandlerWrapper<,>).MakeGenericType(requestType, responseType);
|
||||
|
||||
services.TryAdd(new ServiceDescriptor(typeof(THandler), typeof(THandler), lifetime));
|
||||
services.Add(new ServiceDescriptor(wrapperType,
|
||||
provider => provider.GetService<IServiceFactory>()?.Create(wrapperType,
|
||||
services.TryAdd(new ServiceDescriptor(typeof(THandler), typeof(THandler), lifetime));
|
||||
services.Add(new ServiceDescriptor(
|
||||
wrapperType,
|
||||
provider =>
|
||||
provider.GetService<IServiceFactory>()?.Create(
|
||||
wrapperType,
|
||||
provider.GetRequiredService<THandler>(),
|
||||
provider.GetServices(typeof(IPipelineBehavior<,>).MakeGenericType(requestType, responseType)))!,
|
||||
lifetime
|
||||
));
|
||||
}
|
||||
provider.GetServices(typeof(IPipelineBehavior<,>).MakeGenericType(requestType, responseType))
|
||||
)!,
|
||||
lifetime
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
|
||||
public static IServiceCollection AddNotificationRelay<TFromNotification,
|
||||
TToNotification>(this IServiceCollection services)
|
||||
where TFromNotification :
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace Hyperbar;
|
||||
|
||||
public interface INavigationDescriptor
|
||||
{
|
||||
Type Type { get; set; }
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace Hyperbar;
|
||||
|
||||
public interface INavigationHandler;
|
||||
|
||||
public interface INavigationHandler<TNavigation> :
|
||||
INotificationHandler<Navigate<TNavigation>>,
|
||||
INavigationHandler;
|
||||
@@ -0,0 +1,8 @@
|
||||
|
||||
namespace Hyperbar;
|
||||
|
||||
public record Navigate(object Key) :
|
||||
INotification;
|
||||
|
||||
public record Navigate<TTemplate>(TTemplate Template, object Content) :
|
||||
INotification;
|
||||
@@ -0,0 +1,53 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Hyperbar;
|
||||
|
||||
public class NavigateHandler :
|
||||
INotificationHandler<Navigate>
|
||||
{
|
||||
private readonly IEnumerable<IContentTemplateDescriptor> contentTemplateDescriptors;
|
||||
private readonly IServiceProvider provider;
|
||||
private readonly IMediator mediator;
|
||||
private readonly IEnumerable<INavigationDescriptor> navigationDescriptors;
|
||||
|
||||
public NavigateHandler(IServiceProvider provider,
|
||||
IMediator mediator,
|
||||
IEnumerable<INavigationDescriptor> navigationDescriptors,
|
||||
IEnumerable<IContentTemplateDescriptor> contentTemplateDescriptors)
|
||||
{
|
||||
this.provider = provider;
|
||||
this.mediator = mediator;
|
||||
this.navigationDescriptors = navigationDescriptors;
|
||||
this.contentTemplateDescriptors = contentTemplateDescriptors;
|
||||
}
|
||||
|
||||
public async Task Handle(Navigate args,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
if (contentTemplateDescriptors.FirstOrDefault(x => x.Key == args.Key)
|
||||
is IContentTemplateDescriptor contentTemplateDescriptor)
|
||||
{
|
||||
if (navigationDescriptors.FirstOrDefault(x => contentTemplateDescriptor.TemplateType == x.Type ||
|
||||
contentTemplateDescriptor.TemplateType.BaseType == x.Type) is { } navigationDescriptor)
|
||||
{
|
||||
if (contentTemplateDescriptor.TemplateType == navigationDescriptor.Type ||
|
||||
contentTemplateDescriptor.TemplateType.BaseType == navigationDescriptor.Type)
|
||||
{
|
||||
if (provider.GetRequiredKeyedService(contentTemplateDescriptor.TemplateType,
|
||||
contentTemplateDescriptor.Key) is { } template)
|
||||
{
|
||||
Type navigateType = typeof(Navigate<>)
|
||||
.MakeGenericType(navigationDescriptor.Type);
|
||||
|
||||
if (Activator.CreateInstance(navigateType,
|
||||
new object[] { template, args.Key }) is object navigate)
|
||||
{
|
||||
await mediator.PublishAsync(navigate, cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace Hyperbar;
|
||||
|
||||
public record NavigationDescriptor :
|
||||
INavigationDescriptor
|
||||
{
|
||||
public required Type Type { get; set; }
|
||||
}
|
||||
|
||||
@@ -1,36 +1,5 @@
|
||||
|
||||
namespace Hyperbar;
|
||||
|
||||
public record Remove<TValue>(TValue Value) : INotification;
|
||||
|
||||
public record Navigate(object Key) :
|
||||
INotification;
|
||||
|
||||
public class NavigateHandler :
|
||||
INotificationHandler<Navigate>
|
||||
{
|
||||
private readonly IEnumerable<IContentTemplateDescriptor> descriptors;
|
||||
|
||||
public NavigateHandler(IEnumerable<IContentTemplateDescriptor> descriptors,
|
||||
IServiceProvider provider)
|
||||
{
|
||||
this.descriptors = descriptors;
|
||||
}
|
||||
|
||||
public Task Handle(Navigate args,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
if (descriptors.FirstOrDefault(x => x.Key == args.Key)
|
||||
is IContentTemplateDescriptor descriptor)
|
||||
{
|
||||
//if (provider.GetRequiredKeyedService(descriptor.TemplateType,
|
||||
// descriptor.Key) is { } template)
|
||||
//{
|
||||
// return template;
|
||||
//}
|
||||
}
|
||||
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public record Remove<TValue>(TValue Value) :
|
||||
INotification;
|
||||
@@ -19,12 +19,13 @@ public interface IMediator
|
||||
where TNotification :
|
||||
INotification;
|
||||
|
||||
Task PublishAsync<TNotification>(TNotification notification,
|
||||
Task PublishAsync(object notification,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
Task PublishAsync(object notification,
|
||||
Func<Func<Task>, Task> marshal,
|
||||
object? key = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
where TNotification :
|
||||
INotification;
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
Task PublishAsync<TNotification>(CancellationToken cancellationToken = default)
|
||||
where TNotification :
|
||||
|
||||
@@ -6,5 +6,5 @@ public interface INotificationHandler<in TNotification> :
|
||||
INotification
|
||||
{
|
||||
Task Handle(TNotification args,
|
||||
CancellationToken cancellationToken);
|
||||
CancellationToken cancellationToken = default);
|
||||
}
|
||||
@@ -8,7 +8,7 @@ public class Mediator(IServiceProvider provider,
|
||||
IDispatcher dispatcher) :
|
||||
IMediator
|
||||
{
|
||||
private readonly ConcurrentDictionary<object, List<dynamic>> subscriptions = [];
|
||||
private readonly ConcurrentDictionary<object, List<object>> handlers = [];
|
||||
|
||||
public Task PublishAsync<TNotification>(object key,
|
||||
CancellationToken cancellationToken = default)
|
||||
@@ -36,30 +36,38 @@ public class Mediator(IServiceProvider provider,
|
||||
key, cancellationToken);
|
||||
}
|
||||
|
||||
public Task PublishAsync<TNotification>(TNotification notification,
|
||||
public Task PublishAsync(object notification,
|
||||
Func<Func<Task>, Task> marshal,
|
||||
object? key = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
where TNotification :
|
||||
INotification
|
||||
{
|
||||
List<INotificationHandler<TNotification>> handlers =
|
||||
provider.GetServices<INotificationHandler<TNotification>>().ToList();
|
||||
Type notificationType = notification.GetType();
|
||||
|
||||
foreach (KeyValuePair<object, List<dynamic>> subscriber in subscriptions)
|
||||
List<object?> handlers = provider.GetServices(typeof(INotificationHandler<>)
|
||||
.MakeGenericType(notificationType)).ToList();
|
||||
|
||||
foreach (KeyValuePair<object, List<object>> subscriber in this.handlers)
|
||||
{
|
||||
if (subscriber.Key.Equals($"{(key is not null ? $"{key}:" : "")}{typeof(TNotification)}"))
|
||||
if (subscriber.Key.Equals($"{key?.ToString()}:{notificationType}"))
|
||||
{
|
||||
foreach (dynamic handler in subscriber.Value)
|
||||
{
|
||||
handlers.Add(handler);
|
||||
}
|
||||
handlers.AddRange(subscriber.Value);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (INotificationHandler<TNotification> handler in handlers)
|
||||
foreach (object? handler in handlers)
|
||||
{
|
||||
marshal(() => handler.Handle(notification, cancellationToken));
|
||||
if (handler is not null)
|
||||
{
|
||||
Type? handlerType = handler.GetType();
|
||||
MethodInfo? handleMethod = handlerType.GetMethod("Handle",
|
||||
[notificationType, typeof(CancellationToken)]);
|
||||
|
||||
if (handleMethod is not null)
|
||||
{
|
||||
marshal(() => (Task)handleMethod.Invoke(handler, new object[] { notification,
|
||||
cancellationToken })!);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
@@ -71,6 +79,13 @@ public class Mediator(IServiceProvider provider,
|
||||
new() => PublishAsync(new TNotification(), args => dispatcher.InvokeAsync(async () => await args()),
|
||||
null, cancellationToken);
|
||||
|
||||
public Task PublishAsync(object notification,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
return PublishAsync(notification, args => dispatcher.InvokeAsync(async () => await args()),
|
||||
null, cancellationToken);
|
||||
}
|
||||
|
||||
public Task<TResponse?> SendAsync<TResponse>(IRequest<TResponse> request,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
@@ -116,7 +131,7 @@ public class Mediator(IServiceProvider provider,
|
||||
{
|
||||
if (interfaceType.GetGenericArguments().FirstOrDefault() is Type argumentType)
|
||||
{
|
||||
subscriptions.AddOrUpdate($"{(key is not null ? $"{key}:" : "")}{argumentType}", new List<object> { handler }, (value, collection) =>
|
||||
handlers.AddOrUpdate($"{(key is not null ? $"{key}:" : "")}{argumentType}", new List<object> { handler }, (value, collection) =>
|
||||
{
|
||||
collection.Add(handler);
|
||||
return collection;
|
||||
|
||||
Reference in New Issue
Block a user