diff --git a/Toolkit.Foundation/ActivatedEventArgs.cs b/Toolkit.Foundation/ActivatedEventArgs.cs index 4f1a0b6..99fcacf 100644 --- a/Toolkit.Foundation/ActivatedEventArgs.cs +++ b/Toolkit.Foundation/ActivatedEventArgs.cs @@ -1,3 +1,3 @@ namespace Toolkit.Foundation; -public record ActivatedEventArgs(TSender? Sender = default); +public record ActivatedEventArgs(TSender? Sender = default); \ No newline at end of file diff --git a/Toolkit.Foundation/ConfigurationValueViewModel.cs b/Toolkit.Foundation/ConfigurationValueViewModel.cs index fceeb33..f3b3cc5 100644 --- a/Toolkit.Foundation/ConfigurationValueViewModel.cs +++ b/Toolkit.Foundation/ConfigurationValueViewModel.cs @@ -23,20 +23,14 @@ public partial class ConfigurationValueViewModel(IServic } } - protected override void OnActivated() - { - Value = read(configuration); - base.OnActivated(); - } + protected override void Activated() => Value = read(configuration); - protected override void OnChanged(TValue? value) + protected override void Changed(TValue? value) { if (IsActive) { writer.Write(args => write(value, args)); } - - base.OnChanged(value); } } @@ -97,10 +91,9 @@ public partial class ConfigurationValueViewModel } } - protected override void OnActivated() + protected override void Activated() { Value = read(configuration); - base.OnActivated(); } protected override void OnChanged(TValue? value) diff --git a/Toolkit.Foundation/DefaultHostBuilder.cs b/Toolkit.Foundation/DefaultHostBuilder.cs index 1a792bc..f7d8ce5 100644 --- a/Toolkit.Foundation/DefaultHostBuilder.cs +++ b/Toolkit.Foundation/DefaultHostBuilder.cs @@ -13,8 +13,9 @@ public class DefaultHostBuilder : .ConfigureServices((context, services) => { services.AddScoped(provider => - new ServiceFactory((type, parameters) => ActivatorUtilities.CreateInstance(provider, type, - parameters?.Where(x => x is not null).ToArray()!))); + new ServiceFactory((type, parameters) => + ActivatorUtilities.CreateInstance(provider, type, + parameters?.Where(x => x is not null).ToArray()!))); services.AddSingleton(); diff --git a/Toolkit.Foundation/IActivation.cs b/Toolkit.Foundation/IActivation.cs index 35ceaa1..7c7c007 100644 --- a/Toolkit.Foundation/IActivation.cs +++ b/Toolkit.Foundation/IActivation.cs @@ -4,3 +4,6 @@ public interface IActivation { bool IsActive { get; set; } } + +public interface IActivation : + IActivation; \ No newline at end of file diff --git a/Toolkit.Foundation/Observable.cs b/Toolkit.Foundation/Observable.cs index b5b1423..957582d 100644 --- a/Toolkit.Foundation/Observable.cs +++ b/Toolkit.Foundation/Observable.cs @@ -9,7 +9,7 @@ public partial class Observable(IServiceProvider provider, IDisposer disposer) : ObservableRecipient, IObservableViewModel, - IActivityIndicator, + IActivation, IDisposable, IServiceProviderRequired, IServiceFactoryRequired, @@ -22,10 +22,10 @@ public partial class Observable(IServiceProvider provider, public IServiceFactory Factory { get; } = factory; - public IServiceProvider Provider { get; } = provider; - public new IMessenger Messenger { get; } = messenger; + public IServiceProvider Provider { get; } = provider; + public void Commit() { foreach (object trackedProperty in trackedProperties.Values) @@ -56,6 +56,26 @@ public partial class Observable(IServiceProvider provider, trackedProperties[propertyName] = new TrackedProperty(initialValue, setter, getter); } } + + protected virtual void Activated() + { + } + + protected virtual void Deactivated() + { + } + + protected override sealed void OnActivated() + { + base.OnActivated(); + Activated(); + } + + protected override sealed void OnDeactivated() + { + base.OnDeactivated(); + Deactivated(); + } } public partial class Observable : @@ -73,11 +93,11 @@ public partial class Observable : Value = value; } - protected virtual void OnChanged(TValue? value) + protected virtual void Changed(TValue? value) { } - partial void OnValueChanged(TValue? value) => OnChanged(value); + partial void OnValueChanged(TValue? value) => Changed(value); } public partial class Observable : @@ -100,9 +120,9 @@ public partial class Observable : Value = value; } - protected virtual void OnValueChanged() + protected virtual void ValueChanged() { } - partial void OnValueChanged(TValue? value) => OnValueChanged(); + partial void OnValueChanged(TValue? value) => ValueChanged(); } \ No newline at end of file diff --git a/Toolkit.Foundation/ObservableCollection.cs b/Toolkit.Foundation/ObservableCollection.cs index 1e82901..e475c80 100644 --- a/Toolkit.Foundation/ObservableCollection.cs +++ b/Toolkit.Foundation/ObservableCollection.cs @@ -1,13 +1,15 @@ 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; -public partial class ObservableCollection : +public abstract partial class ObservableCollection : ObservableRecipient, IObservableCollectionViewModel, IList, @@ -36,16 +38,11 @@ public partial class ObservableCollection : private readonly Dictionary trackedProperties = []; + private bool cleaning; + [ObservableProperty] private int count; - private Func? defaultSelectionFactory; - - [ObservableProperty] - private bool initialized; - - private bool isClearing; - [ObservableProperty] private TViewModel? selectedItem; @@ -128,13 +125,7 @@ public partial class ObservableCollection : public TViewModel Add(params object?[] parameters) where T : TViewModel { - T? item = Factory.Create(args => - { - if (args is IInitialization initialization) - { - initialization.Initialize(); - } - }, parameters); + T? item = Factory.Create(parameters); Add(item); return item; @@ -174,11 +165,6 @@ public partial class ObservableCollection : { foreach (TViewModel? item in items) { - if (item is IInitialization initialization) - { - initialization.Initialize(); - } - Add(item); } @@ -187,7 +173,7 @@ public partial class ObservableCollection : public void Clear(bool disposeItems = false) { - isClearing = true; + cleaning = true; if (disposeItems) { foreach (TViewModel item in this.ToList()) @@ -198,12 +184,12 @@ public partial class ObservableCollection : } ClearItems(); - isClearing = false; + cleaning = false; } public void Clear() { - isClearing = true; + cleaning = true; foreach (TViewModel item in this.ToList()) { Disposer.Dispose(item); @@ -211,7 +197,7 @@ public partial class ObservableCollection : } ClearItems(); - isClearing = false; + cleaning = false; } public void Commit() @@ -258,13 +244,7 @@ public partial class ObservableCollection : where T : TViewModel { - T? item = Factory.Create(args => - { - if (args is IInitialization initialization) - { - initialization.Initialize(); - } - }, parameters); + T? item = Factory.Create(parameters); InsertItem(index, item); UpdateSelection(item); @@ -337,10 +317,6 @@ public partial class ObservableCollection : return true; } - public virtual void OnInitialize() - { - } - public void Receive(RemoveEventArgs args) { foreach (TViewModel item in this.ToList()) @@ -447,13 +423,7 @@ public partial class ObservableCollection : index = Count; } - T? item = Factory.Create(args => - { - if (args is IInitialization initialization) - { - initialization.Initialize(); - } - }, parameters); + T? item = Factory.Create(parameters); Insert(index, item); return true; @@ -475,14 +445,6 @@ public partial class ObservableCollection : return true; } - public void Reset(Action> factory, bool disposeItems = true) - { - SelectedItem = default; - - Clear(disposeItems); - factory.Invoke(this); - } - public void Revert() { foreach (object trackedProperty in trackedProperties.Values) @@ -491,26 +453,6 @@ public partial class ObservableCollection : } } - public void SetSource(IList source, Func? defaultSelectionFactory) - { - foreach (TViewModel item in source) - { - Add(item); - } - - if (defaultSelectionFactory is not null) - { - this.defaultSelectionFactory = defaultSelectionFactory; - SelectedItem = defaultSelectionFactory.Invoke(); - } - - if (source is INotifyCollectionChanged observableSource) - { - observableSource.CollectionChanged -= SourceCollectionChanged; - observableSource.CollectionChanged += SourceCollectionChanged; - } - } - public void Track(string propertyName, Func getter, Action setter) { if (!trackedProperties.ContainsKey(propertyName)) @@ -529,7 +471,7 @@ public partial class ObservableCollection : Disposer.Add(this, item); Disposer.Add(item, Disposable.Create(() => { - if (item is IDisposable && !isClearing) + if (item is IDisposable && !cleaning) { if (item is IList collection) { @@ -543,6 +485,26 @@ public partial class ObservableCollection : collection.Insert(index > Count ? Count : index, item); } + protected override sealed void OnActivated() + { + base.OnActivated(); + Activated(); + } + + protected override sealed void OnDeactivated() + { + base.OnDeactivated(); + Deactivated(); + } + + protected virtual void Activated() + { + } + + protected virtual void Deactivated() + { + } + protected virtual void RemoveItem(int index) => collection.RemoveAt(index); @@ -610,11 +572,6 @@ public partial class ObservableCollection : { Add(item); } - - if (defaultSelectionFactory is not null) - { - SelectedItem = defaultSelectionFactory.Invoke(); - } } break; } diff --git a/Toolkit.UI.WinUI/ContentTemplateBinding.cs b/Toolkit.UI.WinUI/ContentTemplateBinding.cs new file mode 100644 index 0000000..0a59d58 --- /dev/null +++ b/Toolkit.UI.WinUI/ContentTemplateBinding.cs @@ -0,0 +1,57 @@ +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Data; +using Toolkit.Foundation; + +namespace Toolkit.UI.WinUI; + +[Bindable] +public static class ContentTemplateBinding +{ + public static readonly DependencyProperty IsAttachedProperty = + DependencyProperty.RegisterAttached("IsAttached", + typeof(bool), typeof(ContentTemplateBinding), + new PropertyMetadata(false, OnAttachLoadedEventChanged)); + + public static bool GetIsAttached(DependencyObject dependencyObject) => + (bool)dependencyObject.GetValue(IsAttachedProperty); + + public static void SetIsAttached(DependencyObject + dependencyObject, bool value) => dependencyObject.SetValue(IsAttachedProperty, value); + + private static void OnAttachLoadedEventChanged(DependencyObject dependencyObject, + DependencyPropertyChangedEventArgs args) + { + if (dependencyObject is FrameworkElement content) + { + void HandleLoaded(object sender, RoutedEventArgs args) + { + if (content.DataContext is IActivation activation) + { + content.Loaded -= HandleLoaded; + activation.IsActive = true; + } + } + + void HandleUnloaded(object sender, RoutedEventArgs args) + { + if (content.DataContext is IActivation activation) + { + content.Unloaded -= HandleUnloaded; + activation.IsActive = false; + } + } + + if ((bool)args.NewValue) + { + content.Loaded += HandleLoaded; + content.Unloaded += HandleUnloaded; + + } + else + { + content.Loaded -= HandleLoaded; + content.Unloaded -= HandleUnloaded; + } + } + } +} \ No newline at end of file diff --git a/Toolkit.WinUI/ContentTemplate.cs b/Toolkit.WinUI/ContentTemplate.cs index 623e03b..914c45f 100644 --- a/Toolkit.WinUI/ContentTemplate.cs +++ b/Toolkit.WinUI/ContentTemplate.cs @@ -38,8 +38,8 @@ public class ContentTemplate : { string xamlString = @$" - + xmlns:Template=""using:{descriptor.TemplateType.Namespace}""> + "; return (DataTemplate)XamlReader.Load(xamlString);