This commit is contained in:
Dan Clark
2024-11-22 18:52:25 +00:00
parent 8a2497be82
commit e809c22cb7
15 changed files with 145 additions and 31 deletions
@@ -37,6 +37,7 @@ public class AsyncHandlerInitialization<TMessage, THandler>(IServiceProvider pro
foreach (IAsyncHandler<TMessage> handler in provider.GetServices<IAsyncHandler<TMessage>>())
{
handler.Handle(args.Message, args.CancellationToken);
args.Reply(Unit.Value);
}
});
}
@@ -34,4 +34,12 @@ public static class IMessengerExtensions
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 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,
TMessage message) where TMessage : class =>
await messenger.Send(new AsyncResponseEventArgs<TMessage, Unit> { Message = message });
}
@@ -43,12 +43,12 @@ public static class IServiceCollectionExtensions
if (key is { Length: > 0 })
{
services.Add(new ServiceDescriptor(typeof(IAsyncHandler<TMessage>), key, typeof(THandler), lifetime));
services.AddInitialization<AsyncHandlerInitialization<TMessage, IAsyncHandler<TMessage>>>(key);
services.AddInitialization<AsyncHandlerKeyedInitialization<TMessage, IAsyncHandler<TMessage>>>(key);
}
else
{
services.Add(new ServiceDescriptor(typeof(IAsyncHandler<TMessage>), typeof(THandler), lifetime));
services.AddInitialization<AsyncHandlerKeyedInitialization<TMessage, IAsyncHandler<TMessage>>>();
services.AddInitialization<AsyncHandlerInitialization<TMessage, IAsyncHandler<TMessage>>>();
}
return services;
+4 -2
View File
@@ -67,13 +67,15 @@ public partial class Observable(IServiceProvider provider,
protected override sealed void OnActivated()
{
base.OnActivated();
Messenger.RegisterAll(this);
Activated();
}
protected override sealed void OnDeactivated()
{
base.OnDeactivated();
Messenger.UnregisterAll(this);
Dispose();
Deactivated();
}
}
+6 -12
View File
@@ -1,10 +1,8 @@
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Messaging;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections;
using System.Collections.Specialized;
using System.Diagnostics.CodeAnalysis;
using System.Reactive.Disposables;
namespace Toolkit.Foundation;
@@ -38,8 +36,6 @@ public abstract partial class ObservableCollection<TViewModel> :
private readonly Dictionary<string, object> trackedProperties = [];
private bool cleaning;
[ObservableProperty]
private int count;
@@ -173,7 +169,6 @@ public abstract partial class ObservableCollection<TViewModel> :
public void Clear(bool disposeItems = false)
{
cleaning = true;
if (disposeItems)
{
foreach (TViewModel item in this.ToList())
@@ -184,12 +179,10 @@ public abstract partial class ObservableCollection<TViewModel> :
}
ClearItems();
cleaning = false;
}
public void Clear()
{
cleaning = true;
foreach (TViewModel item in this.ToList())
{
Disposer.Dispose(item);
@@ -197,7 +190,6 @@ public abstract partial class ObservableCollection<TViewModel> :
}
ClearItems();
cleaning = false;
}
public void Commit()
@@ -222,8 +214,8 @@ public abstract partial class ObservableCollection<TViewModel> :
public virtual void Dispose()
{
GC.SuppressFinalize(this);
Disposer.Dispose(this);
GC.SuppressFinalize(this);
}
public IEnumerator<TViewModel> GetEnumerator() =>
@@ -471,7 +463,7 @@ public abstract partial class ObservableCollection<TViewModel> :
Disposer.Add(this, item);
Disposer.Add(item, Disposable.Create(() =>
{
if (item is IDisposable && !cleaning)
if (item is IDisposable)
{
if (item is IList collection)
{
@@ -487,13 +479,15 @@ public abstract partial class ObservableCollection<TViewModel> :
protected override sealed void OnActivated()
{
base.OnActivated();
Messenger.RegisterAll(this);
Activated();
}
protected override sealed void OnDeactivated()
{
base.OnDeactivated();
Messenger.UnregisterAll(this);
Dispose();
Deactivated();
}
+10
View File
@@ -0,0 +1,10 @@
namespace Toolkit.Foundation;
public record Updated
{
public static UpdatedEventArgs<TValue> As<TValue>(TValue value) =>
new(value);
public static UpdatedEventArgs<TValue> As<TValue>() where TValue : new() =>
new(new TValue());
}
+16
View File
@@ -0,0 +1,16 @@
namespace Toolkit.Foundation;
public record UpdatedEventArgs<TSender>
{
public TSender? Sender { get; }
public UpdatedEventArgs(TSender sender)
{
Sender = sender;
}
public UpdatedEventArgs()
{
}
}
+15 -4
View File
@@ -23,21 +23,33 @@ public static class ContentTemplateBinding
{
if (dependencyObject is FrameworkElement content)
{
IActivation? cachedActivation = null;
void HandleLoaded(object sender, RoutedEventArgs args)
{
if (content.DataContext is IActivation activation)
if (sender is FrameworkElement content)
{
content.Loaded -= HandleLoaded;
if (content.DataContext is IActivation activation)
{
cachedActivation = activation;
activation.IsActive = true;
}
}
}
void HandleUnloaded(object sender, RoutedEventArgs args)
{
if (content.DataContext is IActivation activation)
if (cachedActivation is not null)
{
cachedActivation.IsActive = false;
}
if (sender is FrameworkElement content)
{
cachedActivation = null;
content.Unloaded -= HandleUnloaded;
activation.IsActive = false;
}
}
@@ -45,7 +57,6 @@ public static class ContentTemplateBinding
{
content.Loaded += HandleLoaded;
content.Unloaded += HandleUnloaded;
}
else
{
+36
View File
@@ -0,0 +1,36 @@
using System;
using System.Globalization;
namespace Toolkit.UI.WinUI;
public class StringFormatConverter :
ValueConverter<object, object>
{
public string? StringFormat { get; set; }
protected override object? ConvertTo(object value,
Type? targetType,
object? parameter,
string? language)
{
if (value is null)
{
return null!;
}
if (string.IsNullOrEmpty(StringFormat))
{
return value.ToString()!;
}
try
{
CultureInfo culture = string.IsNullOrWhiteSpace(language) ? CultureInfo.InvariantCulture : new CultureInfo(language);
return string.Format(culture, StringFormat, value);
}
catch
{
return value;
}
}
}
+40
View File
@@ -0,0 +1,40 @@
using Microsoft.UI.Xaml.Data;
using Microsoft.UI.Xaml.Markup;
using System;
namespace Toolkit.UI.WinUI;
public abstract class ValueConverter<TSource, TTarget> :
MarkupExtension,
IValueConverter
{
public object? Convert(object value,
Type targetType,
object parameter,
string language) =>
ConvertTo((TSource)value, targetType, parameter, language);
public object? ConvertBack(object value,
Type targetType,
object parameter,
string language) =>
ConvertBackTo((TTarget)value, targetType, parameter, language);
public TTarget? Convert(TSource value) =>
ConvertTo(value, null, null, null);
public TSource? ConvertBack(TTarget value) =>
ConvertBackTo(value, null, null, null);
protected virtual TTarget? ConvertTo(TSource value,
Type? targetType,
object? parameter,
string? language) => default;
protected virtual TSource? ConvertBackTo(TTarget value,
Type? targetType,
object? parameter,
string? language) => default;
protected override object ProvideValue() => this;
}
-5
View File
@@ -40,11 +40,6 @@ public class ContentControlHandler :
{
activation.IsActive = false;
}
if (content is IDisposable disposable)
{
disposable.Dispose();
}
}
}
@@ -1,4 +1,5 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.UI.Dispatching;
using Microsoft.UI.Xaml.Controls;
using Toolkit.Foundation;
@@ -8,7 +9,7 @@ public static class IServiceCollectionExtensions
{
public static IServiceCollection AddWinUI(this IServiceCollection services)
{
services.AddTransient<IDispatcher, WinUIDispatcher>();
services.AddSingleton<IDispatcher>(provider => new WinUIDispatcher(DispatcherQueue.GetForCurrentThread()));
services.AddTransient<IDispatcherTimerFactory, DispatcherTimerFactory>();
services.AddSingleton<IWindowRegistry, WindowRegistry>();
+2 -2
View File
@@ -3,12 +3,12 @@ using Toolkit.Foundation;
namespace Toolkit.WinUI;
public class WinUIDispatcher :
public class WinUIDispatcher(DispatcherQueue dispatcherQueue) :
IDispatcher
{
public Task Invoke(Action action)
{
DispatcherQueue.GetForCurrentThread().TryEnqueue(action.Invoke);
dispatcherQueue.TryEnqueue(action.Invoke);
return Task.CompletedTask;
}
}