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
@@ -0,0 +1,35 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System;
using TheXamlGuy.Framework.Core;
namespace TheXamlGuy.Framework.WPF
{
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<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,18 @@
using Microsoft.Extensions.DependencyInjection;
using TheXamlGuy.Framework.Core;
namespace TheXamlGuy.Framework.WPF
{
public static class IServiceCollectionExtensions
{
public static IServiceCollection AddRequiredWpf(this IServiceCollection serviceCollection)
{
return serviceCollection
.AddSingleton<IRoute, Route>()
.AddSingleton<IRouteDescriptorCollection, RouteDescriptorCollection>()
.AddSingleton<IRouterContext, Router>()
.AddTransient<IMediatorHandler<Navigate>, NavigateHandler>()
.RegisterHandlers();
}
}
}
@@ -0,0 +1,24 @@
using System.Collections.Generic;
using System.Reflection;
namespace TheXamlGuy.Framework.WPF
{
public static class ObjectExtensions
{
public static T ToObject<T>(this IDictionary<string, object> source) where T : class, new()
{
T? target = new();
if (target.GetType() is { } targetType)
{
foreach (KeyValuePair<string, object> item in source)
{
if (targetType.GetProperty(item.Key) is PropertyInfo propertyInfo)
{
propertyInfo.SetValue(target, item.Value, null);
}
}
}
return target;
}
}
}
@@ -0,0 +1,13 @@
using System;
namespace TheXamlGuy.Framework.WPF;
public class EventInvokedArgs : EventArgs
{
public EventInvokedArgs(object args)
{
Invoked = args;
}
public object Invoked { get; }
}
@@ -0,0 +1,50 @@
using System;
using System.Reflection;
using System.Windows;
using TheXamlGuy.Framework.Core;
using Windows.Foundation;
namespace TheXamlGuy.Framework.WPF;
public class EventSubscriber : DependencyObject, IEventSubscriber
{
public static DependencyProperty TypeProperty =
DependencyProperty.Register(nameof(Type),
typeof(Type), typeof(EventSubscriber));
public event TypedEventHandler<EventSubscriber, EventInvokedArgs>? Invoked;
public Type Type
{
get => (Type)GetValue(TypeProperty);
set => SetValue(TypeProperty, value);
}
public void Subscribe(IEventAggregator eventAggregator)
{
if (eventAggregator is not null)
{
MethodInfo? methodInfo = typeof(EventSubscriber).GetMethod(nameof(EventSubscriber.SubscribeWithType), BindingFlags.NonPublic | BindingFlags.Instance)?.MakeGenericMethod(Type);
methodInfo?.Invoke(this, new object[] { eventAggregator });
}
}
private void SubscribeWithType<TEvent>(IEventAggregator eventAggregator)
{
if (eventAggregator is not null)
{
eventAggregator.SubscribeUI<TEvent>(args =>
{
if (CanInvoke(args))
{
Invoked?.Invoke(this, new EventInvokedArgs(args!));
}
});
}
}
protected virtual bool CanInvoke(object? args)
{
return true;
}
}
@@ -0,0 +1,8 @@
using System.Collections.ObjectModel;
namespace TheXamlGuy.Framework.WPF;
public class EventSubscriberCollection : ObservableCollection<IEventSubscriber>
{
}
@@ -0,0 +1,8 @@
using TheXamlGuy.Framework.Core;
namespace TheXamlGuy.Framework.WPF;
public interface IEventSubscriber
{
void Subscribe(IEventAggregator eventAggregator);
}
+34
View File
@@ -0,0 +1,34 @@
using System.Windows;
namespace TheXamlGuy.Framework.WPF;
public class Interaction
{
public static readonly DependencyProperty XamlEventAggregatorProperty =
DependencyProperty.RegisterAttached("XamlEventAggregator",
typeof(XamlEventAggregator), typeof(Interaction));
public static readonly DependencyProperty InteractiveFrameProperty =
DependencyProperty.RegisterAttached("TouchFrame",
typeof(InteractiveFrame), typeof(Interaction));
public static XamlEventAggregator GetXamlEventAggregator(DependencyObject dependencyObject)
{
return (XamlEventAggregator)dependencyObject.GetValue(XamlEventAggregatorProperty);
}
public static XamlEventAggregator GetInteractiveFrame(DependencyObject dependencyObject)
{
return (XamlEventAggregator)dependencyObject.GetValue(InteractiveFrameProperty);
}
public static void SetXamlEventAggregator(DependencyObject dependencyObject, XamlEventAggregator value)
{
dependencyObject.SetValue(XamlEventAggregatorProperty, value);
}
public static void SetInteractiveFrame(DependencyObject dependencyObject, InteractiveFrame value)
{
dependencyObject.SetValue(InteractiveFrameProperty, value);
}
}
@@ -0,0 +1,72 @@
using System.Collections;
using System.Collections.Specialized;
using System.Windows;
using System.Windows.Markup;
using TheXamlGuy.Framework.Core;
using TheXamlGuy.Framework.WPF.Interactions;
namespace TheXamlGuy.Framework.WPF;
[ContentProperty("Buttons")]
public class InteractiveFrame : DependencyObject
{
public static DependencyProperty ButtonsProperty =
DependencyProperty.Register(nameof(Buttons),
typeof(InteractiveFrameButtonCollection), typeof(InteractiveFrame));
public static DependencyProperty EventAggregatorProperty =
DependencyProperty.Register(nameof(EventAggregator),
typeof(IEventAggregator), typeof(InteractiveFrame), new PropertyMetadata(null, OnEventAggregatorPropertyChanged));
public InteractiveFrame()
{
InteractiveFrameButtonCollection? collection = new();
collection.CollectionChanged += OnCollectionChanged;
SetValue(ButtonsProperty, collection);
}
public InteractiveFrameButtonCollection Buttons
{
get => (InteractiveFrameButtonCollection)GetValue(ButtonsProperty);
set => SetValue(ButtonsProperty, value);
}
public IEventAggregator EventAggregator
{
get => (IEventAggregator)GetValue(EventAggregatorProperty);
set => SetValue(EventAggregatorProperty, value);
}
private static void OnEventAggregatorPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
{
(sender as InteractiveFrame)?.OnEventAggregatorPropertyChanged();
}
private void OnCollectionChanged(object? sender, NotifyCollectionChangedEventArgs args)
{
if (EventAggregator is not null)
{
if (args.NewItems is IList newItems)
{
foreach (object? item in newItems)
{
if (item is InteractiveFrameButton button)
{
button.Register(EventAggregator);
}
}
}
}
}
private void OnEventAggregatorPropertyChanged()
{
if (EventAggregator is not null)
{
foreach (InteractiveFrameButton button in Buttons)
{
button.Register(EventAggregator);
}
}
}
}
@@ -0,0 +1,36 @@
using System;
using System.Windows;
using TheXamlGuy.UI;
using TheXamlGuy.Framework.Core;
using TheXamlGuy.Framework.Microcontroller;
namespace TheXamlGuy.Framework.WPF;
public class InteractiveFrameButton : DependencyObject
{
public static DependencyProperty PlacementProperty =
DependencyProperty.Register(nameof(Type),
typeof(InteractiveFrameButtonPlacement), typeof(InteractiveFrameButton));
public event TypedEventHandler<InteractiveFrameButton, InteractiveFrameButtonInvokedArgs>? Invoked;
public InteractiveFrameButtonPlacement Placement
{
get => (InteractiveFrameButtonPlacement)GetValue(PlacementProperty);
set => SetValue(PlacementProperty, value);
}
public void Register(IEventAggregator eventAggregator)
{
eventAggregator.SubscribeUI<CapactiveSensor>(args =>
{
if ((int)args.Placement == (int)Placement)
{
if (args.State == SensorState.On)
{
Invoked?.Invoke(this, new InteractiveFrameButtonInvokedArgs());
}
}
});
}
}
@@ -0,0 +1,8 @@
using System.Collections.ObjectModel;
namespace TheXamlGuy.Framework.WPF.Interactions;
public class InteractiveFrameButtonCollection : ObservableCollection<InteractiveFrameButton>
{
}
@@ -0,0 +1,8 @@
using System;
namespace TheXamlGuy.Framework.WPF;
public class InteractiveFrameButtonInvokedArgs : EventArgs
{
}
@@ -0,0 +1,9 @@
namespace TheXamlGuy.Framework.WPF;
public enum InteractiveFrameButtonPlacement
{
Left = 0,
Top = 1,
Right = 3,
Bottom = 4,
}
@@ -0,0 +1,72 @@
using System.Collections;
using System.Collections.Specialized;
using System.Windows;
using System.Windows.Markup;
using TheXamlGuy.Framework.Core;
namespace TheXamlGuy.Framework.WPF;
[ContentProperty("Subscribers")]
public class XamlEventAggregator : DependencyObject
{
public static DependencyProperty EventAggregatorProperty =
DependencyProperty.Register(nameof(EventAggregator),
typeof(IEventAggregator), typeof(XamlEventAggregator), new PropertyMetadata(null, OnEventAggregatorPropertyChanged));
public static DependencyProperty SubscribersProperty =
DependencyProperty.Register(nameof(Subscribers),
typeof(EventSubscriberCollection), typeof(XamlEventAggregator));
public XamlEventAggregator()
{
EventSubscriberCollection? collection = new();
collection.CollectionChanged += OnCollectionChanged;
SetValue(SubscribersProperty, collection);
}
public IEventAggregator EventAggregator
{
get => (IEventAggregator)GetValue(EventAggregatorProperty);
set => SetValue(EventAggregatorProperty, value);
}
public EventSubscriberCollection Subscribers
{
get => (EventSubscriberCollection)GetValue(SubscribersProperty);
set => SetValue(SubscribersProperty, value);
}
private static void OnEventAggregatorPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
{
(sender as XamlEventAggregator)?.OnEventAggregatorPropertyChanged();
}
private void OnCollectionChanged(object? sender, NotifyCollectionChangedEventArgs args)
{
if (EventAggregator is not null)
{
if (args.NewItems is IList newItems)
{
foreach (object? item in newItems)
{
if (item is IEventSubscriber subscriber)
{
subscriber.Subscribe(EventAggregator);
}
}
}
}
}
private void OnEventAggregatorPropertyChanged()
{
if (EventAggregator is not null)
{
foreach (IEventSubscriber subscriber in Subscribers)
{
subscriber.Subscribe(EventAggregator);
}
}
}
}
@@ -0,0 +1,46 @@
using System;
using System.Windows;
using System.Windows.Data;
using TheXamlGuy.Framework.Core;
using TheXamlGuy.UI.WPF;
namespace TheXamlGuy.Framework.WPF
{
public class NavigateBackExtension : TriggerExtension
{
private static readonly DependencyProperty EventAggregatorProperty =
DependencyProperty.RegisterAttached("EventAggregator",
typeof(IEventAggregator), typeof(NavigateBackExtension));
private static readonly DependencyProperty RouteProperty =
DependencyProperty.RegisterAttached("Route",
typeof(object), typeof(NavigateBackExtension));
private readonly Binding eventAggregatorBinding;
private readonly Binding routeBinding;
public NavigateBackExtension(object eventAggregator,
object? route)
{
eventAggregatorBinding = eventAggregator.ToBinding();
routeBinding = route.ToBinding();
}
protected override void OnInvoked(object sender, EventArgs args)
{
BindingOperations.SetBinding(TargetObject, EventAggregatorProperty, eventAggregatorBinding);
if (TargetObject?.GetValue(EventAggregatorProperty) is IEventAggregator eventAggregator)
{
BindingOperations.SetBinding(TargetObject, RouteProperty, routeBinding);
if (TargetObject.GetValue(RouteProperty) is { } toTarget)
{
eventAggregator.Publish(new NavigateBack(toTarget));
}
return;
}
base.OnInvoked(sender, args);
}
}
}
+501
View File
@@ -0,0 +1,501 @@
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Data;
using System.Windows.Markup;
using TheXamlGuy.Framework.Core;
using TheXamlGuy.UI;
using TheXamlGuy.UI.WPF;
namespace TheXamlGuy.Framework.WPF;
[ContentProperty("Parameters")]
public class NavigateExtension : TriggerExtension
{
private static readonly DependencyProperty EventAggregatorProperty =
DependencyProperty.RegisterAttached("EventAggregator",
typeof(IEventAggregator), typeof(NavigateExtension));
private static readonly DependencyProperty ParameterProperty =
DependencyProperty.RegisterAttached("Parameter",
typeof(object), typeof(NavigateExtension));
private static readonly DependencyProperty ToProperty =
DependencyProperty.RegisterAttached("To",
typeof(object), typeof(NavigateExtension));
private static readonly DependencyProperty RouteProperty =
DependencyProperty.RegisterAttached("Route",
typeof(object), typeof(NavigateExtension));
private readonly Binding eventAggregatorBinding;
private readonly Binding? toBinding;
private readonly Binding? routeBinding;
private readonly List<object> parameters = new();
public NavigateExtension(object eventAggregator,
object route,
object to)
{
eventAggregatorBinding = eventAggregator.ToBinding();
routeBinding = route.ToBinding();
this.toBinding = to is Binding toBinding ? toBinding : to.ToBinding();
}
public NavigateExtension(object eventAggregator,
object route,
object to,
object args1)
{
eventAggregatorBinding = eventAggregator.ToBinding();
routeBinding = route.ToBinding();
this.toBinding = to is Binding toBinding ? toBinding : to.ToBinding();
parameters.Add(args1 is MarkupExtension ? args1 : args1.ToBinding());
}
public NavigateExtension(object eventAggregator,
object route,
object to,
object args1,
object args2)
{
eventAggregatorBinding = eventAggregator.ToBinding();
routeBinding = route.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 route,
object to,
object args1,
object args2,
object args3)
{
eventAggregatorBinding = eventAggregator.ToBinding();
routeBinding = route.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 route,
object to,
object args1,
object args2,
object args3,
object args4)
{
eventAggregatorBinding = eventAggregator.ToBinding();
routeBinding = route.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 route,
object to,
object args1,
object args2,
object args3,
object args4,
object args5)
{
eventAggregatorBinding = eventAggregator.ToBinding();
routeBinding = route.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 route,
object to,
object args1,
object args2,
object args3,
object args4,
object args5,
object args6)
{
eventAggregatorBinding = eventAggregator.ToBinding();
routeBinding = route.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 route,
object to,
object args1,
object args2,
object args3,
object args4,
object args5,
object args6,
object args7)
{
eventAggregatorBinding = eventAggregator.ToBinding();
routeBinding = route.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 route,
object to,
object args1,
object args2,
object args3,
object args4,
object args5,
object args6,
object args7,
object args8)
{
eventAggregatorBinding = eventAggregator.ToBinding();
routeBinding = route.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 route,
object to,
object args1,
object args2,
object args3,
object args4,
object args5,
object args6,
object args7,
object args8,
object args9)
{
eventAggregatorBinding = eventAggregator.ToBinding();
routeBinding = route.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 route,
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();
routeBinding = route.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 route,
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();
routeBinding = route.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 route,
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();
routeBinding = route.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 route,
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();
routeBinding = route.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 route,
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();
routeBinding = route.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 route,
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();
routeBinding = route.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());
}
protected override void OnInvoked(object sender, EventArgs args)
{
BindingOperations.SetBinding(TargetObject, EventAggregatorProperty, eventAggregatorBinding);
if (TargetObject?.GetValue(EventAggregatorProperty) is IEventAggregator eventAggregator)
{
List<object>? parameters = new();
foreach (object? parameter in this.parameters)
{
switch (parameter)
{
case IParameter keyedParameter:
BindingOperations.SetBinding(TargetObject, ParameterProperty, parameter.ToBinding());
parameters.Add(new KeyValuePair<string, object>(keyedParameter.Key, (dynamic)TargetObject.GetValue(ParameterProperty)));
break;
case IEventParameter eventParameter:
parameters.AddRange(eventParameter.GetParameters(args));
break;
default:
BindingOperations.SetBinding(TargetObject, ParameterProperty, parameter.ToBinding());
parameters.Add((dynamic)TargetObject.GetValue(ParameterProperty));
break;
}
}
BindingOperations.SetBinding(TargetObject, RouteProperty, routeBinding);
if (TargetObject.GetValue(RouteProperty) is { } route)
{
BindingOperations.SetBinding(TargetObject, ToProperty, toBinding);
if (TargetObject.GetValue(ToProperty) is string name)
{
if (toBinding?.StringFormat is { } format)
{
name = string.Format(format, name);
}
eventAggregator.Publish(new Navigate(name, parameters.ToArray()) { Route = route });
}
if (TargetObject.GetValue(ToProperty) is Type type)
{
eventAggregator.Publish(new Navigate(type, parameters.ToArray()) { Route = route });
}
}
return;
}
base.OnInvoked(sender, args);
}
}
@@ -0,0 +1,17 @@
using System.Windows;
namespace TheXamlGuy.Framework.WPF
{
public class NavigationParameter : DependencyObject
{
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register(nameof(Value),
typeof(object), typeof(NavigationParameter));
public object Value
{
get => GetValue(ValueProperty);
set => SetValue(ValueProperty, value);
}
}
}
@@ -0,0 +1,9 @@
using System.Collections.ObjectModel;
namespace TheXamlGuy.Framework.WPF
{
public class NavigationParameterCollection : ObservableCollection<NavigationParameter>
{
}
}
+94
View File
@@ -0,0 +1,94 @@
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Markup;
using TheXamlGuy.UI.WPF;
namespace TheXamlGuy.Framework.WPF
{
[MarkupExtensionReturnType(typeof(Control))]
public class RouteExtension : MarkupExtension
{
private static readonly DependencyProperty RouteProperty =
DependencyProperty.RegisterAttached("Route",
typeof(IRoute), typeof(RouteExtension));
private readonly string name;
private readonly Binding routeBinding;
private PropertyChangedRevoker? dataContextPropertyChangedRevoker;
public RouteExtension(object route, string name)
{
routeBinding = route.ToBinding();
this.name = name;
}
private bool TryGetDataContext(DependencyObject target, out object dataContext)
{
dataContext = target.GetValue(FrameworkElement.DataContextProperty) ?? target.GetValue(FrameworkContentElement.DataContextProperty);
return dataContext is not null;
}
public override object? ProvideValue(IServiceProvider serviceProvider)
{
if (dataContextPropertyChangedRevoker is not null)
{
dataContextPropertyChangedRevoker.Dispose();
dataContextPropertyChangedRevoker = null;
}
if (serviceProvider.GetService(typeof(IProvideValueTarget)) is IProvideValueTarget target)
{
if (target.TargetObject is FrameworkElement frameworkElement)
{
if (!TryGetDataContext(frameworkElement, out object dataContext))
{
dataContextPropertyChangedRevoker = new PropertyChangedRevoker(frameworkElement, FrameworkElement.DataContextProperty, OnDataContextPropertyChangedChanged);
void OnDataContextPropertyChangedChanged(object sender, DependencyPropertyChangedEventArgs _)
{
if (TryGetDataContext(frameworkElement, out dataContext))
{
frameworkElement.Loaded -= HandleLoaded;
BindingOperations.SetBinding(frameworkElement, RouteProperty, routeBinding);
if (frameworkElement?.GetValue(RouteProperty) is IRoute route)
{
route.AddRoute(name, frameworkElement);
BindingOperations.ClearBinding(frameworkElement, RouteProperty);
}
}
}
void HandleLoaded(object sender, RoutedEventArgs args)
{
frameworkElement.Loaded -= HandleLoaded;
if (TryGetDataContext(frameworkElement, out dataContext))
{
BindingOperations.SetBinding(frameworkElement, RouteProperty, routeBinding);
if (frameworkElement?.GetValue(RouteProperty) is IRoute route)
{
route.AddRoute(name, frameworkElement);
BindingOperations.ClearBinding(frameworkElement, RouteProperty);
}
}
}
frameworkElement.Loaded += HandleLoaded;
}
else
{
BindingOperations.SetBinding(frameworkElement, RouteProperty, routeBinding);
if (frameworkElement?.GetValue(RouteProperty) is IRoute route)
{
route.AddRoute(name, frameworkElement);
BindingOperations.ClearBinding(frameworkElement, RouteProperty);
}
}
}
}
return null;
}
}
}
+5
View File
@@ -0,0 +1,5 @@
using System.Windows;
using System.Windows.Markup;
[assembly: ThemeInfo(ResourceDictionaryLocation.None, ResourceDictionaryLocation.SourceAssembly)]
[assembly: XmlnsDefinition("http://schemas.microsoft.com/winfx/2006/xaml/presentation", "TheXamlGuy.Framework.WPF")]
+9
View File
@@ -0,0 +1,9 @@
using System.Collections.Generic;
namespace TheXamlGuy.Framework.WPF
{
public interface IRoute
{
void AddRoute(string name, object route);
}
}
+11
View File
@@ -0,0 +1,11 @@
using System.Collections.Generic;
namespace TheXamlGuy.Framework.WPF
{
public interface IRouteDescriptor
{
object Route { get; }
string? Name { get; }
}
}
@@ -0,0 +1,9 @@
using System.Collections.Generic;
namespace TheXamlGuy.Framework.WPF
{
public interface IRouteDescriptorCollection : IList<IRouteDescriptor>
{
}
}
+20
View File
@@ -0,0 +1,20 @@
using TheXamlGuy.Framework.Core;
using TheXamlGuy.Framework.Core;
namespace TheXamlGuy.Framework.WPF
{
public class NavigateHandler : IMediatorHandler<Navigate>
{
private readonly IEventAggregator eventAggregator;
public NavigateHandler(IEventAggregator eventAggregator)
{
this.eventAggregator = eventAggregator;
}
public void Handle(Navigate request)
{
eventAggregator.Publish(request);
}
}
}
+33
View File
@@ -0,0 +1,33 @@
using System.Collections.Generic;
namespace TheXamlGuy.Framework.WPF
{
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);
}
}
}
+38
View File
@@ -0,0 +1,38 @@
using System.Linq;
using System.Windows;
namespace TheXamlGuy.Framework.WPF
{
public class Route : IRoute
{
private readonly IRouteDescriptorCollection routes;
public Route(IRouteDescriptorCollection routes)
{
this.routes = routes;
}
public void AddRoute(string name, object route)
{
if (route is FrameworkElement frameworkElement)
{
void HandleUnloaded(object sender, RoutedEventArgs args)
{
if (routes.FirstOrDefault(x => x.Route == sender) is IRouteDescriptor descriptor)
{
routes.Remove(descriptor);
}
}
frameworkElement.Unloaded += HandleUnloaded;
}
if (routes.FirstOrDefault(x => x.Name == name) is IRouteDescriptor descriptor)
{
routes.Remove(descriptor);
}
routes.Add(new RouteDescriptor(name, route));
}
}
}
+15
View File
@@ -0,0 +1,15 @@
namespace TheXamlGuy.Framework.WPF
{
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,12 @@
using System.Collections.Generic;
namespace TheXamlGuy.Framework.WPF
{
public class RouteDescriptorCollection : List<IRouteDescriptor>, IRouteDescriptorCollection
{
public RouteDescriptorCollection(IEnumerable<IRouteDescriptor> collection) : base(collection)
{
}
}
}
+124
View File
@@ -0,0 +1,124 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using TheXamlGuy.Framework.Core;
namespace TheXamlGuy.Framework.WPF
{
public class Router : IRouterContext
{
private readonly IRouteDescriptorCollection descriptors;
private readonly IDisposer disposer;
private readonly IEventAggregator eventAggregator;
private readonly INamedDataTemplateFactory namedDataTemplateFactory;
private readonly INamedTemplateFactory namedTemplateFactory;
private readonly ITemplateFactory templateFactory;
private readonly ITypedDataTemplateFactory typedDataTemplateFactory;
public Router(ITemplateFactory templateFactory,
INamedTemplateFactory namedTemplateFactory,
INamedDataTemplateFactory namedDataTemplateFactory,
ITypedDataTemplateFactory typedDataTemplateFactory,
IEventAggregator eventAggregator,
IDisposer disposer,
IRouteDescriptorCollection descriptors)
{
this.templateFactory = templateFactory;
this.namedTemplateFactory = namedTemplateFactory;
this.namedDataTemplateFactory = namedDataTemplateFactory;
this.typedDataTemplateFactory = typedDataTemplateFactory;
this.eventAggregator = eventAggregator;
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? dataTemplate = 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)
{
dataTemplate = namedDataTemplateFactory.Create(name, parameters.ToArray());
template = namedTemplateFactory.Create(name);
}
if (args.Type is Type type)
{
dataTemplate = typedDataTemplateFactory.Create(type, parameters.ToArray());
template = templateFactory.Create(dataTemplate);
}
if (template is FrameworkElement content)
{
content.DataContext = dataTemplate;
if (descriptors.FirstOrDefault(x => args.Route is string { } name && name == x.Name) is RouteDescriptor descriptor)
{
if (descriptor.Route is Frame frame)
{
frame.Navigate(content);
}
if (descriptor.Route is ContentControl contentControl)
{
contentControl.Content = content;
}
}
eventAggregator.Publish(Navigated.Create((dynamic?)content, (dynamic?)dataTemplate, keyedParameters));
}
else
{
if (descriptors.FirstOrDefault(x => args.Route is string { } name && name == x.Name) is { Route: 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: FrameworkElement content })
{
if (content.DataContext is IDisposable disposable)
{
disposable.Dispose();
}
}
if (descriptor.Route is Frame frame)
{
frame.GoBack();
}
}
}
}
}
@@ -0,0 +1,53 @@
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using TheXamlGuy.Framework.Core;
using TheXamlGuy.UI.WPF;
namespace TheXamlGuy.Framework.WPF
{
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;
}
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
if (item is not null)
{
if (dataTracking.TryGetValue(item, out DataTemplate? cachedDataTemplate))
{
return cachedDataTemplate;
}
if (templateFactory.Create(item) is FrameworkElement template)
{
if (TemplateGenerator.CreateDataTemplate(() => template) is DataTemplate dataTemplate)
{
template.DataContext = item;
dataTemplate.Seal();
if (template is ICachable cachable)
{
dataTracking[item!] = dataTemplate;
}
eventAggregator.Publish(Navigated.Create((dynamic?)template, (dynamic?)item));
return dataTemplate;
}
}
}
return base.SelectTemplate(item, container);
}
}
}
+17
View File
@@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0-windows10.0.18362.0</TargetFramework>
<Nullable>enable</Nullable>
<UseWPF>true</UseWPF>
<RootNamespace>TheXamlGuy.Framework.WPF</RootNamespace>
<AssemblyName>TheXamlGuy.Framework.WPF</AssemblyName>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="7.0.0-rc.2.22472.3" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\UI\WPF\WPF.csproj" />
<ProjectReference Include="..\Core\Core.csproj" />
<ProjectReference Include="..\Microcontroller\Microcontroller.csproj" />
</ItemGroup>
</Project>