This commit is contained in:
Dan Clark
2024-11-23 21:41:59 +00:00
parent e809c22cb7
commit 911ed375b4
17 changed files with 311 additions and 18 deletions
@@ -9,7 +9,7 @@ public class AsyncHandlerInitialization<TMessage, TResponse, THandler>(IServiceP
{
public void Initialize()
{
if (!StrongReferenceMessenger.Default.IsRegistered<ResponseEventArgs<TMessage, TResponse>>(provider))
if (!StrongReferenceMessenger.Default.IsRegistered<AsyncResponseEventArgs<TMessage, TResponse>>(provider))
{
StrongReferenceMessenger.Default.Register<IServiceProvider, AsyncResponseEventArgs<TMessage, TResponse>>(provider,
(provider, args) =>
@@ -29,7 +29,7 @@ public class AsyncHandlerInitialization<TMessage, THandler>(IServiceProvider pro
{
public void Initialize()
{
if (!StrongReferenceMessenger.Default.IsRegistered<TMessage>(provider))
if (!StrongReferenceMessenger.Default.IsRegistered<AsyncResponseEventArgs<TMessage, Unit>>(provider))
{
StrongReferenceMessenger.Default.Register<IServiceProvider, AsyncResponseEventArgs<TMessage, Unit>>(provider,
(provider, args) =>
@@ -9,14 +9,15 @@ public class AsyncHandlerKeyedInitialization<TMessage, THandler>(string key, ISe
{
public void Initialize()
{
if (!StrongReferenceMessenger.Default.IsRegistered<TMessage, string>(provider, key))
if (!StrongReferenceMessenger.Default.IsRegistered<AsyncResponseEventArgs<TMessage, Unit>, string>(provider, key))
{
StrongReferenceMessenger.Default.Register<IServiceProvider, TMessage, string>(provider, key,
StrongReferenceMessenger.Default.Register<IServiceProvider, AsyncResponseEventArgs<TMessage, Unit>, string>(provider, key,
(provider, args) =>
{
foreach (IAsyncHandler<TMessage> handler in provider.GetKeyedServices<IAsyncHandler<TMessage>>(key))
{
handler.Handle(args);
handler.Handle(args.Message, args.CancellationToken);
args.Reply(Unit.Value);
}
});
}
@@ -29,14 +30,14 @@ public class AsyncHandlerKeyedInitialization<TMessage, TResponse, THandler>(stri
{
public void Initialize()
{
if (!StrongReferenceMessenger.Default.IsRegistered<ResponseEventArgs<TMessage, TResponse>, string>(provider, key))
if (!StrongReferenceMessenger.Default.IsRegistered<AsyncResponseEventArgs<TMessage, TResponse>, string>(provider, key))
{
StrongReferenceMessenger.Default.Register<IServiceProvider, ResponseEventArgs<TMessage, TResponse>, string>(provider, key,
StrongReferenceMessenger.Default.Register<IServiceProvider, AsyncResponseEventArgs<TMessage, TResponse>, string>(provider, key,
(provider, args) =>
{
foreach (IAsyncHandler<TMessage, TResponse> handler in provider.GetKeyedServices<IAsyncHandler<TMessage, TResponse>>(key))
{
handler.Handle(args.Message);
args.Reply(handler.Handle(args.Message, args.CancellationToken));
}
});
}
@@ -1,4 +1,4 @@
namespace Toolkit.UI.Avalonia;
namespace Toolkit.Foundation;
public enum ForwardChaining
{
@@ -1,4 +1,4 @@
namespace Toolkit.UI.Avalonia;
namespace Toolkit.Foundation;
public interface ICondition
{
@@ -0,0 +1,6 @@
namespace Toolkit.Foundation;
public interface IDisposableApplication
{
void Dispose();
}
@@ -31,15 +31,31 @@ public static class IMessengerExtensions
where TMessage : class, new() =>
await messenger.Send(new AsyncResponseEventArgs<TMessage, TResponse> { Message = new TMessage() });
public static async Task<TResponse> SendAsync<TMessage, TResponse>(this IMessenger messenger,
string key) where TMessage : class, new() =>
await messenger.Send(new AsyncResponseEventArgs<TMessage, TResponse> { Message = new TMessage() }, key);
public static async Task<TResponse> SendAsync<TMessage, TResponse>(this IMessenger messenger,
TMessage message) where TMessage : class =>
await messenger.Send(new AsyncResponseEventArgs<TMessage, TResponse> { Message = message });
public static async Task<TResponse> SendAsync<TMessage, TResponse>(this IMessenger messenger,
TMessage message, string key) where TMessage : class =>
await messenger.Send(new AsyncResponseEventArgs<TMessage, TResponse> { Message = message }, key);
public static async Task SendAsync<TMessage>(this IMessenger messenger)
where TMessage : class, new() =>
await messenger.Send(new AsyncResponseEventArgs<TMessage, Unit> { Message = new TMessage() });
public static async Task SendAsync<TMessage>(this IMessenger messenger,
string key) where TMessage : class, new() =>
await messenger.Send(new AsyncResponseEventArgs<TMessage, Unit> { Message = new TMessage() }, key);
public static async Task SendAsync<TMessage>(this IMessenger messenger,
TMessage message) where TMessage : class =>
await messenger.Send(new AsyncResponseEventArgs<TMessage, Unit> { Message = message });
public static async Task SendAsync<TMessage>(this IMessenger messenger,
TMessage message, string key) where TMessage : class =>
await messenger.Send(new AsyncResponseEventArgs<TMessage, Unit> { Message = message }, key);
}
+3 -5
View File
@@ -485,10 +485,10 @@ public abstract partial class ObservableCollection<TViewModel> :
protected override sealed void OnDeactivated()
{
Messenger.UnregisterAll(this);
Dispose();
Messenger.UnregisterAll(this);
Deactivated();
Dispose();
}
protected virtual void Activated()
@@ -525,8 +525,6 @@ public abstract partial class ObservableCollection<TViewModel> :
{
newSelection.IsSelected = true;
}
Messenger.Send(Selection.As(SelectedItem));
}
private void SourceCollectionChanged(object? sender,
+2 -1
View File
@@ -1,5 +1,6 @@
using Avalonia;
using Avalonia.Xaml.Interactivity;
using Toolkit.Foundation;
namespace Toolkit.UI.Avalonia;
@@ -35,5 +36,5 @@ public class ComparisonCondition :
}
public bool Evaluate() => ComparisonLogic.Evaluate(LeftOperand,
Operator, RightOperand);
Operator, RightOperand);
}
+1
View File
@@ -1,6 +1,7 @@
using Avalonia;
using Avalonia.Metadata;
using Avalonia.Xaml.Interactivity;
using Toolkit.Foundation;
namespace Toolkit.UI.Avalonia;
@@ -1,5 +1,6 @@
using Avalonia;
using Avalonia.Metadata;
using Toolkit.Foundation;
namespace Toolkit.UI.Avalonia;
+46
View File
@@ -0,0 +1,46 @@
using Microsoft.UI.Xaml;
using Microsoft.Xaml.Interactions.Core;
using Toolkit.Foundation;
namespace Toolkit.UI.WinUI;
public class ComparisonCondition :
DependencyObject,
ICondition
{
public static readonly DependencyProperty LeftOperandProperty =
DependencyProperty.Register(nameof(LeftOperand),
typeof(object), typeof(ComparisonCondition),
new PropertyMetadata(null));
public static readonly DependencyProperty OperatorProperty =
DependencyProperty.Register(nameof(Operator),
typeof(ComparisonConditionType), typeof(ComparisonCondition),
new PropertyMetadata(null));
public static readonly DependencyProperty RightOperandProperty =
DependencyProperty.Register(nameof(RightOperand),
typeof(object), typeof(ComparisonCondition),
new PropertyMetadata(null));
public object LeftOperand
{
get => GetValue(LeftOperandProperty);
set => SetValue(LeftOperandProperty, value);
}
public object RightOperand
{
get => GetValue(RightOperandProperty);
set => SetValue(RightOperandProperty, value);
}
public ComparisonConditionType Operator
{
get => (ComparisonConditionType)GetValue(OperatorProperty);
set => SetValue(OperatorProperty, value);
}
public bool Evaluate() =>
ComparisonLogic.Evaluate(LeftOperand, Operator, RightOperand);
}
+100
View File
@@ -0,0 +1,100 @@
using Microsoft.Xaml.Interactions.Core;
using System;
using System.ComponentModel;
using System.Globalization;
namespace Toolkit.UI.WinUI;
internal static class ComparisonLogic
{
internal static bool Evaluate(object leftOperand,
ComparisonConditionType operatorType,
object? rightOperand)
{
bool result = false;
if (leftOperand != null)
{
Type leftType = leftOperand.GetType();
if (rightOperand != null)
{
TypeConverter typeConverter = TypeDescriptor.GetConverter(leftType);
rightOperand = typeConverter.ConvertFrom(rightOperand);
}
}
if (leftOperand is IComparable leftComparableOperand &&
rightOperand is IComparable rightComparableOperand)
{
return EvaluateComparable(leftComparableOperand, operatorType, rightComparableOperand);
}
switch (operatorType)
{
case ComparisonConditionType.Equal:
result = Equals(leftOperand, rightOperand);
break;
case ComparisonConditionType.NotEqual:
result = !Equals(leftOperand, rightOperand);
break;
}
return result;
}
private static bool EvaluateComparable(IComparable leftOperand,
ComparisonConditionType operatorType,
IComparable rightOperand)
{
object? convertedOperand = null;
try
{
convertedOperand = Convert.ChangeType(rightOperand, leftOperand.GetType(), CultureInfo.CurrentCulture);
}
catch (FormatException)
{
}
catch (InvalidCastException)
{
}
if (convertedOperand == null)
{
return operatorType == ComparisonConditionType.NotEqual;
}
int comparison = leftOperand.CompareTo((IComparable)convertedOperand);
bool result = false;
switch (operatorType)
{
case ComparisonConditionType.Equal:
result = comparison == 0;
break;
case ComparisonConditionType.GreaterThan:
result = comparison > 0;
break;
case ComparisonConditionType.GreaterThanOrEqual:
result = comparison >= 0;
break;
case ComparisonConditionType.LessThan:
result = comparison < 0;
break;
case ComparisonConditionType.LessThanOrEqual:
result = comparison <= 0;
break;
case ComparisonConditionType.NotEqual:
result = comparison != 0;
break;
}
return result;
}
}
+42
View File
@@ -0,0 +1,42 @@
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Markup;
using Microsoft.Xaml.Interactivity;
using Toolkit.Foundation;
namespace Toolkit.UI.WinUI;
[ContentProperty(Name = nameof(Actions))]
public class ConditionAction :
DependencyObject,
IAction
{
public static readonly DependencyProperty ActionsProperty =
DependencyProperty.Register(nameof(Actions),
typeof(ActionCollection), typeof(ConditionAction),
new PropertyMetadata(null));
public static readonly DependencyProperty ConditionProperty =
DependencyProperty.Register(nameof(Condition),
typeof(ICondition), typeof(ConditionAction),
new PropertyMetadata(null));
private ActionCollection? actions;
public ActionCollection Actions => actions ??= [];
public ICondition? Condition
{
get => (ICondition?)GetValue(ConditionProperty);
set => SetValue(ConditionProperty, value);
}
public object? Execute(object? sender, object? parameter)
{
if (Condition?.Evaluate() == true)
{
Interaction.ExecuteActions(sender, Actions, parameter);
}
return true;
}
}
+8
View File
@@ -0,0 +1,8 @@
using System.Collections.ObjectModel;
namespace Toolkit.UI.WinUI;
public class ConditionCollection :
ObservableCollection<ComparisonCondition>
{
}
+56
View File
@@ -0,0 +1,56 @@
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Markup;
using Toolkit.Foundation;
namespace Toolkit.UI.WinUI;
[ContentProperty(Name = nameof(Conditions))]
public class ConditionalExpression :
DependencyObject,
ICondition
{
public static readonly DependencyProperty ConditionsProperty =
DependencyProperty.Register(nameof(Conditions),
typeof(ConditionCollection), typeof(ConditionalExpression),
new PropertyMetadata(new ConditionCollection()));
public static readonly DependencyProperty ForwardChainingProperty =
DependencyProperty.Register(nameof(ForwardChaining),
typeof(ForwardChaining), typeof(ConditionalExpression),
new PropertyMetadata(ForwardChaining.And));
public ConditionalExpression()
{
SetValue(ConditionsProperty, new ConditionCollection());
}
public ConditionCollection Conditions =>
(ConditionCollection)GetValue(ConditionsProperty);
public ForwardChaining ForwardChaining
{
get => (ForwardChaining)GetValue(ForwardChainingProperty);
set => SetValue(ForwardChainingProperty, value);
}
public bool Evaluate()
{
bool result = false;
foreach (var operation in Conditions)
{
result = operation.Evaluate();
if (!result && ForwardChaining == ForwardChaining.And)
{
return false;
}
if (result && ForwardChaining == ForwardChaining.Or)
{
return true;
}
}
return result;
}
}
+2 -1
View File
@@ -3,7 +3,8 @@ using System.Diagnostics.CodeAnalysis;
namespace Toolkit.WinUI;
public interface IWindowRegistry
public interface IWindowRegistry :
IDisposable
{
void Add(Window window);
+17 -1
View File
@@ -1,9 +1,11 @@
using Microsoft.UI.Xaml;
using System.Diagnostics.CodeAnalysis;
using System.Reactive.Disposables;
using Toolkit.Foundation;
namespace Toolkit.WinUI;
public class WindowRegistry :
public class WindowRegistry(IDisposer disposer) :
IWindowRegistry
{
private readonly List<Window> windows = [];
@@ -19,13 +21,27 @@ public class WindowRegistry :
}
windows.Add(window);
disposer.Add(this, Disposable.Create(() =>
{
windows.Remove(window);
window.Close();
}));
window.Closed += OnWindowClosed;
}
}
public void Dispose()
{
disposer.Dispose(this);
GC.SuppressFinalize(this);
}
public bool TryGet<TWindow>([DisallowNull] out TWindow? window)
where TWindow : Window
{
window = windows.OfType<TWindow>().FirstOrDefault() ?? null;
return window is not null;
}