Add project files.

This commit is contained in:
Daniel Clark
2022-11-01 15:26:08 +00:00
parent daa7b59f22
commit 7e4f880821
408 changed files with 16863 additions and 0 deletions
+27
View File
@@ -0,0 +1,27 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<RootNamespace>TheXamlGuy.Framework.Avalonia</RootNamespace>
<AssemblyName>TheXamlGuy.Framework.Avalonia</AssemblyName>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Avalonia" Version="11.0.0-preview3" />
<PackageReference Include="MicroCom.Runtime" Version="0.10.5" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\UI\Avalonia\Avalonia.csproj" />
<ProjectReference Include="..\Core\Core.csproj" />
</ItemGroup>
<ItemGroup>
<Reference Include="FluentAvalonia">
<HintPath>References\FluentAvalonia.dll</HintPath>
</Reference>
</ItemGroup>
</Project>
@@ -0,0 +1,34 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using TheXamlGuy.Framework.Core;
namespace TheXamlGuy.Framework.Avalonia;
public static class IHostBuilderExtensions
{
public static IHostBuilder ConfigureTemplates(this IHostBuilder hostBuilder, Action<ITemplateBuilder> builderDelegate)
{
hostBuilder.ConfigureServices((hostBuilderContext, serviceCollection) =>
{
TemplateBuilder? builder = new();
builderDelegate?.Invoke(builder);
serviceCollection
.AddSingleton(builder.Descriptors)
.AddSingleton<ITemplateDescriptorProvider, TemplateDescriptorProvider>()
.AddSingleton<ITemplateFactory, TemplateFactory>()
.AddSingleton<INamedTemplateFactory, NamedTemplateFactory>()
.AddSingleton<ITypedDataTemplateFactory, TypedDataTemplateFactory>()
.AddSingleton<INamedDataTemplateFactory, NamedDataTemplateFactory>()
.AddSingleton<ITemplateSelector, TemplateSelector>();
foreach (ITemplateDescriptor? descriptor in builder.Descriptors)
{
serviceCollection.Add(new ServiceDescriptor(descriptor.TemplateType, descriptor.TemplateType, descriptor.Lifetime));
serviceCollection.Add(new ServiceDescriptor(descriptor.DataType, descriptor.DataType, descriptor.Lifetime));
}
});
return hostBuilder;
}
}
@@ -0,0 +1,17 @@
using Microsoft.Extensions.DependencyInjection;
using TheXamlGuy.Framework.Core;
namespace TheXamlGuy.Framework.Avalonia;
public static class IServiceCollectionExtensions
{
public static IServiceCollection AddRequiredAvalonia(this IServiceCollection serviceCollection)
{
return serviceCollection
.AddSingleton<IRouter, Router>()
.AddSingleton<IRouteDescriptorCollection, RouteDescriptorCollection>()
.AddSingleton<IRouterContext, RouterContext>()
.AddTransient<IMediatorHandler<Navigate>, NavigateHandler>()
.RegisterHandlers();
}
}
@@ -0,0 +1,453 @@
using Avalonia.Controls;
using Avalonia;
using Avalonia.Data;
using Avalonia.Markup.Xaml;
using TheXamlGuy.Framework.Core;
using TheXamlGuy.UI.Avalonia;
namespace TheXamlGuy.Framework.Avalonia;
public class NavigateExtension : TriggerExtension
{
private static readonly AttachedProperty<IEventAggregator> EventAggregatorProperty =
AvaloniaProperty.RegisterAttached<NavigateExtension, Control, IEventAggregator>("EventAggregator");
private static readonly AttachedProperty<object> ParameterProperty =
AvaloniaProperty.RegisterAttached<NavigateExtension, Control, object>("Parameter");
private static readonly AvaloniaProperty RouteProperty =
AvaloniaProperty.RegisterAttached<NavigateExtension, Control, object>("Route");
private static readonly AvaloniaProperty ToProperty =
AvaloniaProperty.RegisterAttached<NavigateExtension, Control, object>("To");
private readonly Binding eventAggregatorBinding;
private readonly List<object> parameters = new();
private readonly Binding toBinding;
private object? route;
private Binding? routeBinding;
public NavigateExtension(object eventAggregator,
object to)
{
eventAggregatorBinding = eventAggregator.ToBinding();
this.toBinding = to is Binding toBinding ? toBinding : to.ToBinding();
}
public NavigateExtension(object eventAggregator,
object to,
object args1)
{
eventAggregatorBinding = eventAggregator.ToBinding();
this.toBinding = to is Binding toBinding ? toBinding : to.ToBinding();
parameters.Add(args1 is MarkupExtension ? args1 : args1.ToBinding());
}
public NavigateExtension(object eventAggregator,
object to,
object args1,
object args2)
{
eventAggregatorBinding = eventAggregator.ToBinding();
this.toBinding = to is Binding toBinding ? toBinding : to.ToBinding();
parameters.Add(args1 is MarkupExtension ? args1 : args1.ToBinding());
parameters.Add(args2 is MarkupExtension ? args2 : args2.ToBinding());
}
public NavigateExtension(object eventAggregator,
object to,
object args1,
object args2,
object args3)
{
eventAggregatorBinding = eventAggregator.ToBinding();
this.toBinding = to is Binding toBinding ? toBinding : to.ToBinding();
parameters.Add(args1 is MarkupExtension ? args1 : args1.ToBinding());
parameters.Add(args2 is MarkupExtension ? args2 : args2.ToBinding());
parameters.Add(args3 is MarkupExtension ? args3 : args3.ToBinding());
}
public NavigateExtension(object eventAggregator,
object to,
object args1,
object args2,
object args3,
object args4)
{
eventAggregatorBinding = eventAggregator.ToBinding();
this.toBinding = to is Binding toBinding ? toBinding : to.ToBinding();
parameters.Add(args1 is MarkupExtension ? args1 : args1.ToBinding());
parameters.Add(args2 is MarkupExtension ? args2 : args2.ToBinding());
parameters.Add(args3 is MarkupExtension ? args3 : args3.ToBinding());
parameters.Add(args4 is MarkupExtension ? args4 : args4.ToBinding());
}
public NavigateExtension(object eventAggregator,
object to,
object args1,
object args2,
object args3,
object args4,
object args5)
{
eventAggregatorBinding = eventAggregator.ToBinding();
this.toBinding = to is Binding toBinding ? toBinding : to.ToBinding();
parameters.Add(args1 is MarkupExtension ? args1 : args1.ToBinding());
parameters.Add(args2 is MarkupExtension ? args2 : args2.ToBinding());
parameters.Add(args3 is MarkupExtension ? args3 : args3.ToBinding());
parameters.Add(args4 is MarkupExtension ? args4 : args4.ToBinding());
parameters.Add(args5 is MarkupExtension ? args5 : args5.ToBinding());
}
public NavigateExtension(object eventAggregator,
object to,
object args1,
object args2,
object args3,
object args4,
object args5,
object args6)
{
eventAggregatorBinding = eventAggregator.ToBinding();
this.toBinding = to is Binding toBinding ? toBinding : to.ToBinding();
parameters.Add(args1 is MarkupExtension ? args1 : args1.ToBinding());
parameters.Add(args2 is MarkupExtension ? args2 : args2.ToBinding());
parameters.Add(args3 is MarkupExtension ? args3 : args3.ToBinding());
parameters.Add(args4 is MarkupExtension ? args4 : args4.ToBinding());
parameters.Add(args5 is MarkupExtension ? args5 : args5.ToBinding());
parameters.Add(args6 is MarkupExtension ? args6 : args6.ToBinding());
}
public NavigateExtension(object eventAggregator,
object to,
object args1,
object args2,
object args3,
object args4,
object args5,
object args6,
object args7)
{
eventAggregatorBinding = eventAggregator.ToBinding();
this.toBinding = to is Binding toBinding ? toBinding : to.ToBinding();
parameters.Add(args1 is MarkupExtension ? args1 : args1.ToBinding());
parameters.Add(args2 is MarkupExtension ? args2 : args2.ToBinding());
parameters.Add(args3 is MarkupExtension ? args3 : args3.ToBinding());
parameters.Add(args4 is MarkupExtension ? args4 : args4.ToBinding());
parameters.Add(args5 is MarkupExtension ? args5 : args5.ToBinding());
parameters.Add(args6 is MarkupExtension ? args6 : args6.ToBinding());
parameters.Add(args7 is MarkupExtension ? args7 : args7.ToBinding());
}
public NavigateExtension(object eventAggregator,
object to,
object args1,
object args2,
object args3,
object args4,
object args5,
object args6,
object args7,
object args8)
{
eventAggregatorBinding = eventAggregator.ToBinding();
this.toBinding = to is Binding toBinding ? toBinding : to.ToBinding();
parameters.Add(args1 is MarkupExtension ? args1 : args1.ToBinding());
parameters.Add(args2 is MarkupExtension ? args2 : args2.ToBinding());
parameters.Add(args3 is MarkupExtension ? args3 : args3.ToBinding());
parameters.Add(args4 is MarkupExtension ? args4 : args4.ToBinding());
parameters.Add(args5 is MarkupExtension ? args5 : args5.ToBinding());
parameters.Add(args6 is MarkupExtension ? args6 : args6.ToBinding());
parameters.Add(args7 is MarkupExtension ? args7 : args7.ToBinding());
parameters.Add(args8 is MarkupExtension ? args8 : args8.ToBinding());
}
public NavigateExtension(object eventAggregator,
object to,
object args1,
object args2,
object args3,
object args4,
object args5,
object args6,
object args7,
object args8,
object args9)
{
eventAggregatorBinding = eventAggregator.ToBinding();
this.toBinding = to is Binding toBinding ? toBinding : to.ToBinding();
parameters.Add(args1 is MarkupExtension ? args1 : args1.ToBinding());
parameters.Add(args2 is MarkupExtension ? args2 : args2.ToBinding());
parameters.Add(args3 is MarkupExtension ? args3 : args3.ToBinding());
parameters.Add(args4 is MarkupExtension ? args4 : args4.ToBinding());
parameters.Add(args5 is MarkupExtension ? args5 : args5.ToBinding());
parameters.Add(args6 is MarkupExtension ? args6 : args6.ToBinding());
parameters.Add(args7 is MarkupExtension ? args7 : args7.ToBinding());
parameters.Add(args8 is MarkupExtension ? args8 : args8.ToBinding());
parameters.Add(args9 is MarkupExtension ? args9 : args9.ToBinding());
}
public NavigateExtension(object eventAggregator,
object to,
object args1,
object args2,
object args3,
object args4,
object args5,
object args6,
object args7,
object args8,
object args9,
object args10)
{
eventAggregatorBinding = eventAggregator.ToBinding();
this.toBinding = to is Binding toBinding ? toBinding : to.ToBinding();
parameters.Add(args1 is MarkupExtension ? args1 : args1.ToBinding());
parameters.Add(args2 is MarkupExtension ? args2 : args2.ToBinding());
parameters.Add(args3 is MarkupExtension ? args3 : args3.ToBinding());
parameters.Add(args4 is MarkupExtension ? args4 : args4.ToBinding());
parameters.Add(args5 is MarkupExtension ? args5 : args5.ToBinding());
parameters.Add(args6 is MarkupExtension ? args6 : args6.ToBinding());
parameters.Add(args7 is MarkupExtension ? args7 : args7.ToBinding());
parameters.Add(args8 is MarkupExtension ? args8 : args8.ToBinding());
parameters.Add(args9 is MarkupExtension ? args9 : args9.ToBinding());
parameters.Add(args10 is MarkupExtension ? args10 : args10.ToBinding());
}
public NavigateExtension(object eventAggregator,
object to,
object args1,
object args2,
object args3,
object args4,
object args5,
object args6,
object args7,
object args8,
object args9,
object args10,
object args11)
{
eventAggregatorBinding = eventAggregator.ToBinding();
this.toBinding = to is Binding toBinding ? toBinding : to.ToBinding();
parameters.Add(args1 is MarkupExtension ? args1 : args1.ToBinding());
parameters.Add(args2 is MarkupExtension ? args2 : args2.ToBinding());
parameters.Add(args3 is MarkupExtension ? args3 : args3.ToBinding());
parameters.Add(args4 is MarkupExtension ? args4 : args4.ToBinding());
parameters.Add(args5 is MarkupExtension ? args5 : args5.ToBinding());
parameters.Add(args6 is MarkupExtension ? args6 : args6.ToBinding());
parameters.Add(args7 is MarkupExtension ? args7 : args7.ToBinding());
parameters.Add(args8 is MarkupExtension ? args8 : args8.ToBinding());
parameters.Add(args9 is MarkupExtension ? args9 : args9.ToBinding());
parameters.Add(args10 is MarkupExtension ? args10 : args10.ToBinding());
parameters.Add(args11 is MarkupExtension ? args11 : args11.ToBinding());
}
public NavigateExtension(object eventAggregator,
object to,
object args1,
object args2,
object args3,
object args4,
object args5,
object args6,
object args7,
object args8,
object args9,
object args10,
object args11,
object args12)
{
eventAggregatorBinding = eventAggregator.ToBinding();
this.toBinding = to is Binding toBinding ? toBinding : to.ToBinding();
parameters.Add(args1 is MarkupExtension ? args1 : args1.ToBinding());
parameters.Add(args2 is MarkupExtension ? args2 : args2.ToBinding());
parameters.Add(args3 is MarkupExtension ? args3 : args3.ToBinding());
parameters.Add(args4 is MarkupExtension ? args4 : args4.ToBinding());
parameters.Add(args5 is MarkupExtension ? args5 : args5.ToBinding());
parameters.Add(args6 is MarkupExtension ? args6 : args6.ToBinding());
parameters.Add(args7 is MarkupExtension ? args7 : args7.ToBinding());
parameters.Add(args8 is MarkupExtension ? args8 : args8.ToBinding());
parameters.Add(args9 is MarkupExtension ? args9 : args9.ToBinding());
parameters.Add(args10 is MarkupExtension ? args10 : args10.ToBinding());
parameters.Add(args11 is MarkupExtension ? args11 : args11.ToBinding());
parameters.Add(args12 is MarkupExtension ? args12 : args12.ToBinding());
}
public NavigateExtension(object eventAggregator,
object to,
object args1,
object args2,
object args3,
object args4,
object args5,
object args6,
object args7,
object args8,
object args9,
object args10,
object args11,
object args12,
object args13)
{
eventAggregatorBinding = eventAggregator.ToBinding();
this.toBinding = to is Binding toBinding ? toBinding : to.ToBinding();
parameters.Add(args1 is MarkupExtension ? args1 : args1.ToBinding());
parameters.Add(args2 is MarkupExtension ? args2 : args2.ToBinding());
parameters.Add(args3 is MarkupExtension ? args3 : args3.ToBinding());
parameters.Add(args4 is MarkupExtension ? args4 : args4.ToBinding());
parameters.Add(args5 is MarkupExtension ? args5 : args5.ToBinding());
parameters.Add(args6 is MarkupExtension ? args6 : args6.ToBinding());
parameters.Add(args7 is MarkupExtension ? args7 : args7.ToBinding());
parameters.Add(args8 is MarkupExtension ? args8 : args8.ToBinding());
parameters.Add(args9 is MarkupExtension ? args9 : args9.ToBinding());
parameters.Add(args10 is MarkupExtension ? args10 : args10.ToBinding());
parameters.Add(args11 is MarkupExtension ? args11 : args11.ToBinding());
parameters.Add(args12 is MarkupExtension ? args12 : args12.ToBinding());
parameters.Add(args13 is MarkupExtension ? args13 : args13.ToBinding());
}
public NavigateExtension(object eventAggregator,
object to,
object args1,
object args2,
object args3,
object args4,
object args5,
object args6,
object args7,
object args8,
object args9,
object args10,
object args11,
object args12,
object args13,
object args14)
{
eventAggregatorBinding = eventAggregator.ToBinding();
this.toBinding = to is Binding toBinding ? toBinding : to.ToBinding();
parameters.Add(args1 is MarkupExtension ? args1 : args1.ToBinding());
parameters.Add(args2 is MarkupExtension ? args2 : args2.ToBinding());
parameters.Add(args3 is MarkupExtension ? args3 : args3.ToBinding());
parameters.Add(args4 is MarkupExtension ? args4 : args4.ToBinding());
parameters.Add(args5 is MarkupExtension ? args5 : args5.ToBinding());
parameters.Add(args6 is MarkupExtension ? args6 : args6.ToBinding());
parameters.Add(args7 is MarkupExtension ? args7 : args7.ToBinding());
parameters.Add(args8 is MarkupExtension ? args8 : args8.ToBinding());
parameters.Add(args9 is MarkupExtension ? args9 : args9.ToBinding());
parameters.Add(args10 is MarkupExtension ? args10 : args10.ToBinding());
parameters.Add(args11 is MarkupExtension ? args11 : args11.ToBinding());
parameters.Add(args12 is MarkupExtension ? args12 : args12.ToBinding());
parameters.Add(args13 is MarkupExtension ? args13 : args13.ToBinding());
parameters.Add(args14 is MarkupExtension ? args14 : args14.ToBinding());
}
public NavigateExtension(object eventAggregator,
object to,
object args1,
object args2,
object args3,
object args4,
object args5,
object args6,
object args7,
object args8,
object args9,
object args10,
object args11,
object args12,
object args13,
object args14,
object args15)
{
eventAggregatorBinding = eventAggregator.ToBinding();
this.toBinding = to is Binding toBinding ? toBinding : to.ToBinding();
parameters.Add(args1 is MarkupExtension ? args1 : args1.ToBinding());
parameters.Add(args2 is MarkupExtension ? args2 : args2.ToBinding());
parameters.Add(args3 is MarkupExtension ? args3 : args3.ToBinding());
parameters.Add(args4 is MarkupExtension ? args4 : args4.ToBinding());
parameters.Add(args5 is MarkupExtension ? args5 : args5.ToBinding());
parameters.Add(args6 is MarkupExtension ? args6 : args6.ToBinding());
parameters.Add(args7 is MarkupExtension ? args7 : args7.ToBinding());
parameters.Add(args8 is MarkupExtension ? args8 : args8.ToBinding());
parameters.Add(args9 is MarkupExtension ? args9 : args9.ToBinding());
parameters.Add(args10 is MarkupExtension ? args10 : args10.ToBinding());
parameters.Add(args11 is MarkupExtension ? args11 : args11.ToBinding());
parameters.Add(args12 is MarkupExtension ? args12 : args12.ToBinding());
parameters.Add(args13 is MarkupExtension ? args13 : args13.ToBinding());
parameters.Add(args14 is MarkupExtension ? args14 : args14.ToBinding());
parameters.Add(args15 is MarkupExtension ? args15 : args15.ToBinding());
}
public object? Route
{
get
{
return route;
}
set
{
route = value;
if (route is not null)
{
routeBinding = route.ToBinding();
}
}
}
protected override void OnInvoked(object sender, EventArgs args)
{
if (TargetObject is not null)
{
TargetObject.Bind(EventAggregatorProperty, eventAggregatorBinding);
if (TargetObject.GetValue(EventAggregatorProperty) is IEventAggregator eventAggregator)
{
TargetObject.Bind(ToProperty, toBinding);
if (TargetObject.GetValue(ToProperty) is { } to)
{
object? route = null;
if (routeBinding is not null)
{
TargetObject.Bind(RouteProperty, routeBinding);
route = TargetObject.GetValue(RouteProperty);
}
if (to is string name)
{
if (toBinding?.StringFormat is string format)
{
name = string.Format(format, name);
}
eventAggregator.Publish(new Navigate(name, parameters.ToArray()) { Route = route });
}
if (to is Type type)
{
eventAggregator.Publish(new Navigate(type, parameters.ToArray()) { Route = route });
}
}
}
base.OnInvoked(sender, args);
}
}
}
@@ -0,0 +1,86 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Data;
using Avalonia.Interactivity;
using Avalonia.Markup.Xaml;
using TheXamlGuy.UI.Avalonia;
namespace TheXamlGuy.Framework.Avalonia;
public class RouteExtension : MarkupExtension
{
private static readonly AttachedProperty<object> RouteProperty =
AvaloniaProperty.RegisterAttached<RouteExtension, Control, object>("Route");
private readonly string name;
private readonly Binding routeBinding;
public RouteExtension(object route, string name)
{
routeBinding = route.ToBinding();
this.name = name;
}
private bool TryGetBinding(AvaloniaObject sender, out object? binding)
{
binding = sender.GetValue(StyledElement.DataContextProperty);
return binding is not null;
}
public override object? ProvideValue(IServiceProvider serviceProvider)
{
if (serviceProvider.GetService(typeof(IProvideValueTarget)) is IProvideValueTarget target)
{
if (target.TargetObject is TemplatedControl control)
{
if (!TryGetBinding(control, out object? binding))
{
void HandleDataContextChanged(object? sender, EventArgs args)
{
if (TryGetBinding(control, out binding))
{
control.Loaded -= HandleLoaded;
control.Bind(RouteProperty, routeBinding);
if (control?.GetValue(RouteProperty) is IRouter route)
{
route.Add(name, control);
control.ClearValue(RouteProperty);
}
}
}
control.DataContextChanged += HandleDataContextChanged;
void HandleLoaded(object? sender, RoutedEventArgs args)
{
control.Loaded -= HandleLoaded;
if (TryGetBinding(control, out binding))
{
control.Bind(RouteProperty, routeBinding);
if (control?.GetValue(RouteProperty) is IRouter route)
{
route.Add(name, control);
control.ClearValue(RouteProperty);
}
}
}
control.Loaded += HandleLoaded;
}
else
{
control.Bind(RouteProperty, routeBinding);
if (control?.GetValue(RouteProperty) is IRouter route)
{
route.Add(name, control);
control.ClearValue(RouteProperty);
}
}
}
}
return null;
}
}
@@ -0,0 +1,3 @@
using Avalonia.Metadata;
[assembly: XmlnsDefinition("https://github.com/avaloniaui", "TheXamlGuy.Framework.Avalonia")]
Binary file not shown.
@@ -0,0 +1,30 @@
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using FluentAvalonia.UI.Controls;
namespace TheXamlGuy.Framework.Avalonia;
public class ContentDialogRouteHandler : RouteHandler<ContentDialog>
{
public override async void Handle(Route<ContentDialog> request)
{
if (request.Template is ContentDialog contentDialog)
{
contentDialog.DataContext = request.Data;
await contentDialog.ShowAsync();
}
}
}
public class ContentControlRouteHandler : RouteHandler<ContentControl>
{
public override void Handle(Route<ContentControl> request)
{
if (request.Template is TemplatedControl control)
{
control.DataContext = request.Data;
request.Target.Content = control;
}
}
}
@@ -0,0 +1,26 @@
using Avalonia.Controls.Primitives;
using FluentAvalonia.UI.Controls;
using FluentAvalonia.UI.Navigation;
namespace TheXamlGuy.Framework.Avalonia;
public class FrameRouteHandler : RouteHandler<Frame>
{
public override void Handle(Route<Frame> request)
{
if (request.Template is Type type)
{
void HandleNavigated(object sender, NavigationEventArgs args)
{
request.Target.Navigated -= HandleNavigated;
if (request.Target.Content is TemplatedControl control)
{
control.DataContext = request.Data;
}
}
request.Target.Navigated += HandleNavigated;
request.Target.Navigate(type);
}
}
}
@@ -0,0 +1,8 @@
namespace TheXamlGuy.Framework.Avalonia;
public interface IRouteDescriptor
{
object Route { get; }
string? Name { get; }
}
@@ -0,0 +1,6 @@
namespace TheXamlGuy.Framework.Avalonia;
public interface IRouteDescriptorCollection : IList<IRouteDescriptor>
{
}
+6
View File
@@ -0,0 +1,6 @@
namespace TheXamlGuy.Framework.Avalonia;
public interface IRouter
{
void Add(string name, object route);
}
@@ -0,0 +1,19 @@
using TheXamlGuy.Framework.Core;
namespace TheXamlGuy.Framework.Avalonia
{
public class NavigateHandler : IMediatorHandler<Navigate>
{
private readonly IEventAggregator eventAggregator;
public NavigateHandler(IEventAggregator eventAggregator)
{
this.eventAggregator = eventAggregator;
}
public void Handle(Navigate request)
{
eventAggregator.Publish(request);
}
}
}
+30
View File
@@ -0,0 +1,30 @@
namespace TheXamlGuy.Framework.Avalonia;
public class Navigated<TContent, TDataContext> where TContent : class where TDataContext : class
{
public Navigated()
{
}
public Navigated(TContent content, TDataContext dataContext, IDictionary<string, object>? parameters = null)
{
Content = content;
DataContext = dataContext;
Parameters = parameters;
}
public TContent? Content { get; }
public TDataContext? DataContext { get; }
public IDictionary<string, object>? Parameters { get; }
}
public class Navigated
{
public static Navigated<TContent, TDataTemplate> Create<TContent, TDataTemplate>(TContent content, TDataTemplate dataContext, IDictionary<string, object>? parameters = null) where TContent : class where TDataTemplate : class
{
return new Navigated<TContent, TDataTemplate>(content, dataContext, parameters);
}
}
+5
View File
@@ -0,0 +1,5 @@
using Avalonia.Controls.Primitives;
namespace TheXamlGuy.Framework.Avalonia;
public record Route<TTarget>(TTarget Target, object? Data, object? Template) where TTarget : TemplatedControl;
@@ -0,0 +1,14 @@
namespace TheXamlGuy.Framework.Avalonia;
public record RouteDescriptor : IRouteDescriptor
{
public RouteDescriptor(string name, object route)
{
Name = name;
Route = route;
}
public string Name { get; }
public object Route { get; }
}
@@ -0,0 +1,9 @@
namespace TheXamlGuy.Framework.Avalonia;
public class RouteDescriptorCollection : List<IRouteDescriptor>, IRouteDescriptorCollection
{
public RouteDescriptorCollection(IEnumerable<IRouteDescriptor> collection) : base(collection)
{
}
}
@@ -0,0 +1,9 @@
using Avalonia.Controls.Primitives;
using TheXamlGuy.Framework.Core;
namespace TheXamlGuy.Framework.Avalonia;
public abstract class RouteHandler<TTarget> : IMediatorHandler<Route<TTarget>> where TTarget : TemplatedControl
{
public abstract void Handle(Route<TTarget> request);
}
+37
View File
@@ -0,0 +1,37 @@
using Avalonia.Controls.Primitives;
using Avalonia.Interactivity;
namespace TheXamlGuy.Framework.Avalonia;
public class Router : IRouter
{
private readonly IRouteDescriptorCollection routes;
public Router(IRouteDescriptorCollection routes)
{
this.routes = routes;
}
public void Add(string name, object route)
{
if (route is TemplatedControl control)
{
void HandleUnloaded(object? sender, RoutedEventArgs args)
{
if (routes.FirstOrDefault(x => x.Route == sender) is IRouteDescriptor descriptor)
{
routes.Remove(descriptor);
}
}
control.Unloaded += HandleUnloaded;
}
if (routes.FirstOrDefault(x => x.Name == name) is IRouteDescriptor descriptor)
{
routes.Remove(descriptor);
}
routes.Add(new RouteDescriptor(name, route));
}
}
+133
View File
@@ -0,0 +1,133 @@
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using FluentAvalonia.UI.Controls;
using TheXamlGuy.Framework.Core;
namespace TheXamlGuy.Framework.Avalonia;
public class RouterContext : IRouterContext
{
private readonly IRouteDescriptorCollection descriptors;
private readonly IDisposer disposer;
private readonly IEventAggregator eventAggregator;
private readonly IMediator mediator;
private readonly INamedDataTemplateFactory namedDataTemplateFactory;
private readonly INamedTemplateFactory namedTemplateFactory;
private readonly ITemplateDescriptorProvider templateDescriptorProvider;
private readonly ITemplateFactory templateFactory;
private readonly ITypedDataTemplateFactory typedDataTemplateFactory;
public RouterContext(ITemplateDescriptorProvider templateDescriptorProvider,
ITemplateFactory templateFactory,
INamedTemplateFactory namedTemplateFactory,
INamedDataTemplateFactory namedDataTemplateFactory,
ITypedDataTemplateFactory typedDataTemplateFactory,
IEventAggregator eventAggregator,
IMediator mediator,
IDisposer disposer,
IRouteDescriptorCollection descriptors)
{
this.templateDescriptorProvider = templateDescriptorProvider;
this.templateFactory = templateFactory;
this.namedTemplateFactory = namedTemplateFactory;
this.namedDataTemplateFactory = namedDataTemplateFactory;
this.typedDataTemplateFactory = typedDataTemplateFactory;
this.eventAggregator = eventAggregator;
this.mediator = mediator;
this.disposer = disposer;
this.descriptors = descriptors;
}
public async Task InitializeAsync()
{
disposer.Add(this, eventAggregator.Current.SubscribeUI<Navigate>(OnNavigate));
disposer.Add(this, eventAggregator.Current.SubscribeUI<NavigateBack>(OnNavigateBack));
await Task.CompletedTask;
}
private void OnNavigate(Navigate args)
{
object? data = null;
object? template = null;
Dictionary<string, object> keyedParameters = new();
List<object> parameters = new();
foreach (object? parameter in args.Parameters)
{
if (parameter is KeyValuePair<string, object> keyed)
{
keyedParameters.Add(keyed.Key, keyed.Value);
}
else
{
parameters.Add(parameter);
}
}
if (args.Name is { Length: > 0 } name)
{
data = namedDataTemplateFactory.Create(name, parameters.ToArray());
template = descriptors.FirstOrDefault(x => args.Route is string { } name && name == x.Name) is { Route: Frame } ? templateDescriptorProvider.Get(name)?.TemplateType : namedTemplateFactory.Create(name);
}
if (args.Type is Type type)
{
data = typedDataTemplateFactory.Create(type, parameters.ToArray());
template = descriptors.FirstOrDefault(x => args.Route is string { } name && name == x.Name) is { Route: Frame } ? templateDescriptorProvider.Get(type)?.TemplateType : templateFactory.Create(data);
}
if (template is not null)
{
if (template is ContentDialog contentDialog)
{
mediator.Handle(new Route<ContentDialog>(contentDialog, data, template));
}
else
{
if (descriptors.FirstOrDefault(x => args.Route is string { } name && name == x.Name) is RouteDescriptor descriptor)
{
switch (descriptor.Route)
{
case Frame frame:
mediator.Handle(new Route<Frame>(frame, data, template));
break;
case ContentControl contentControl:
mediator.Handle(new Route<ContentControl>(contentControl, data, template));
break;
}
}
}
}
else
{
if (descriptors.FirstOrDefault(x => args.Route is string { } name && name == x.Name) is RouteDescriptor descriptor)
{
if (descriptor.Route is ContentControl contentControl)
{
contentControl.Content = null;
}
}
}
}
private void OnNavigateBack(NavigateBack args)
{
if (descriptors.FirstOrDefault(x => args.Route is string { } name && name == x.Name) is RouteDescriptor descriptor)
{
if (descriptor.Route is ContentControl { Content: TemplatedControl content })
{
if (content.DataContext is IDisposable disposable)
{
disposable.Dispose();
}
}
if (descriptor.Route is Frame frame)
{
frame.GoBack();
}
}
}
}
@@ -0,0 +1,47 @@
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Controls.Templates;
using Avalonia.Markup.Xaml.Templates;
using FluentAvalonia.UI.Controls;
using TheXamlGuy.Framework.Core;
namespace TheXamlGuy.Framework.Avalonia;
public class TemplateSelector : DataTemplateSelector, ITemplateSelector
{
private readonly Dictionary<object, DataTemplate> dataTracking = new();
private readonly ITemplateFactory templateFactory;
private readonly IEventAggregator eventAggregator;
public TemplateSelector(ITemplateFactory templateFactory,
IEventAggregator eventAggregator)
{
this.templateFactory = templateFactory;
this.eventAggregator = eventAggregator;
}
protected override IDataTemplate SelectTemplateCore(object item, IControl container)
{
if (item is not null)
{
if (dataTracking.TryGetValue(item, out DataTemplate? cachedDataTemplate))
{
return cachedDataTemplate;
}
return new FuncDataTemplate(item.GetType(), (value, namescope) =>
{
if (templateFactory.Create(item) is TemplatedControl template)
{
return template;
}
return null;
});
}
return base.SelectTemplateCore(item, container);
}
}