introduce a TransientNavigationStore to share objects from one state to the next state
This commit is contained in:
@@ -7,7 +7,7 @@ using Toolkit.UI.Controls.Avalonia;
|
|||||||
|
|
||||||
namespace Toolkit.Avalonia;
|
namespace Toolkit.Avalonia;
|
||||||
|
|
||||||
public class FrameHandler :
|
public class FrameHandler(ITransientNavigationStore<Frame> navigationStore) :
|
||||||
INotificationHandler<NavigateEventArgs<Frame>>,
|
INotificationHandler<NavigateEventArgs<Frame>>,
|
||||||
INotificationHandler<NavigateBackEventArgs<Frame>>
|
INotificationHandler<NavigateBackEventArgs<Frame>>
|
||||||
{
|
{
|
||||||
@@ -18,19 +18,16 @@ public class FrameHandler :
|
|||||||
frame.NavigationPageFactory ??= new NavigationPageFactory();
|
frame.NavigationPageFactory ??= new NavigationPageFactory();
|
||||||
if (args.Template is Control control)
|
if (args.Template is Control control)
|
||||||
{
|
{
|
||||||
void NavigatedTo(Control sender)
|
void Navigated(Control sender)
|
||||||
{
|
{
|
||||||
async void HandleNavigatedTo(object? _,
|
async void HandleNavigatedTo(object? _, NavigationEventArgs __)
|
||||||
NavigationEventArgs __)
|
|
||||||
{
|
{
|
||||||
async void HandleNavigatingFrom(object? _,
|
async void HandleNavigatingFrom(object? _, NavigatingCancelEventArgs args)
|
||||||
NavigatingCancelEventArgs args)
|
|
||||||
{
|
{
|
||||||
sender.RemoveHandler(Frame.NavigatingFromEvent, HandleNavigatingFrom);
|
sender.RemoveHandler(Frame.NavigatingFromEvent, HandleNavigatingFrom);
|
||||||
control.Unloaded -= HandleUnloaded;
|
control.Unloaded -= HandleUnloaded;
|
||||||
|
|
||||||
async void HandleNavigatedFrom(object? _,
|
async void HandleNavigatedFrom(object? _, NavigationEventArgs args)
|
||||||
NavigationEventArgs args)
|
|
||||||
{
|
{
|
||||||
sender.RemoveHandler(Frame.NavigatedFromEvent, HandleNavigatedFrom);
|
sender.RemoveHandler(Frame.NavigatedFromEvent, HandleNavigatedFrom);
|
||||||
if (sender.DataContext is object content)
|
if (sender.DataContext is object content)
|
||||||
@@ -40,9 +37,11 @@ public class FrameHandler :
|
|||||||
await deactivated.OnDeactivated();
|
await deactivated.OnDeactivated();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (content is not IKeepAlive)
|
|
||||||
{
|
|
||||||
if (content is IDisposable disposable)
|
if (content is IDisposable disposable)
|
||||||
|
{
|
||||||
|
FrameNavigationOptions? options = navigationStore.Get<FrameNavigationOptions>(frame);
|
||||||
|
if (options is not FrameNavigationOptions frameOptions ||
|
||||||
|
!frameOptions.IsNavigationStackEnabled)
|
||||||
{
|
{
|
||||||
disposable.Dispose();
|
disposable.Dispose();
|
||||||
}
|
}
|
||||||
@@ -51,6 +50,7 @@ public class FrameHandler :
|
|||||||
}
|
}
|
||||||
|
|
||||||
sender.AddHandler(Frame.NavigatedFromEvent, HandleNavigatedFrom);
|
sender.AddHandler(Frame.NavigatedFromEvent, HandleNavigatedFrom);
|
||||||
|
|
||||||
if (sender.DataContext is object content)
|
if (sender.DataContext is object content)
|
||||||
{
|
{
|
||||||
if (content is IConfirmation confirmation &&
|
if (content is IConfirmation confirmation &&
|
||||||
@@ -106,7 +106,6 @@ public class FrameHandler :
|
|||||||
}
|
}
|
||||||
|
|
||||||
control.DataContext = args.Content;
|
control.DataContext = args.Content;
|
||||||
NavigatedTo(control);
|
|
||||||
|
|
||||||
FrameNavigationOptions navigationOptions = new();
|
FrameNavigationOptions navigationOptions = new();
|
||||||
List<Action> postNavigateActions = [];
|
List<Action> postNavigateActions = [];
|
||||||
@@ -133,22 +132,19 @@ public class FrameHandler :
|
|||||||
|
|
||||||
if (args.Parameters is not null)
|
if (args.Parameters is not null)
|
||||||
{
|
{
|
||||||
if (args.Parameters.TryGetValue("Transition",
|
if (args.Parameters.TryGetValue("Transition", out object? transition))
|
||||||
out object? transition))
|
|
||||||
{
|
{
|
||||||
switch ($"{transition}")
|
switch ($"{transition}")
|
||||||
{
|
{
|
||||||
case "Suppress":
|
case "Suppress":
|
||||||
navigationOptions.TransitionInfoOverride =
|
navigationOptions.TransitionInfoOverride = new SuppressNavigationTransitionInfo();
|
||||||
new SuppressNavigationTransitionInfo();
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "FromLeft":
|
case "FromLeft":
|
||||||
case "FromRight":
|
case "FromRight":
|
||||||
case "FromTop":
|
case "FromTop":
|
||||||
case "FromBottom":
|
case "FromBottom":
|
||||||
navigationOptions.TransitionInfoOverride =
|
navigationOptions.TransitionInfoOverride = new SlideNavigationTransitionInfo
|
||||||
new SlideNavigationTransitionInfo
|
|
||||||
{
|
{
|
||||||
Effect = Enum.Parse<SlideNavigationTransitionEffect>($"{transition}")
|
Effect = Enum.Parse<SlideNavigationTransitionEffect>($"{transition}")
|
||||||
};
|
};
|
||||||
@@ -156,8 +152,7 @@ public class FrameHandler :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args.Parameters.TryGetValue("IsBackStackEnabled",
|
if (args.Parameters.TryGetValue("IsBackStackEnabled", out object? isBackStackEnabled))
|
||||||
out object? isBackStackEnabled))
|
|
||||||
{
|
{
|
||||||
if (isBackStackEnabled is bool value)
|
if (isBackStackEnabled is bool value)
|
||||||
{
|
{
|
||||||
@@ -165,8 +160,7 @@ public class FrameHandler :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args.Parameters.TryGetValue("ClearBackStack",
|
if (args.Parameters.TryGetValue("ClearBackStack", out object? clearBackStack))
|
||||||
out object? clearBackStack))
|
|
||||||
{
|
{
|
||||||
if (clearBackStack is bool clearBool)
|
if (clearBackStack is bool clearBool)
|
||||||
{
|
{
|
||||||
@@ -178,8 +172,7 @@ public class FrameHandler :
|
|||||||
|
|
||||||
if (clearBackStack is string clearString)
|
if (clearBackStack is string clearString)
|
||||||
{
|
{
|
||||||
if (clearString.StartsWith('[') && clearString.EndsWith(']') &&
|
if (clearString.StartsWith('[') && clearString.EndsWith(']') && clearString.Contains('-'))
|
||||||
clearString.Contains('-'))
|
|
||||||
{
|
{
|
||||||
string range = clearString.Trim('[', ']');
|
string range = clearString.Trim('[', ']');
|
||||||
string[] parts = range.Split('-');
|
string[] parts = range.Split('-');
|
||||||
@@ -202,6 +195,9 @@ public class FrameHandler :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Navigated(control);
|
||||||
|
|
||||||
|
navigationStore.Set(frame, navigationOptions);
|
||||||
frame.NavigateFromObject(control, navigationOptions);
|
frame.NavigateFromObject(control, navigationOptions);
|
||||||
|
|
||||||
foreach (Action postAction in postNavigateActions)
|
foreach (Action postAction in postNavigateActions)
|
||||||
|
|||||||
@@ -33,7 +33,10 @@ public static class IServiceCollectionExtensions
|
|||||||
services.AddHandler<ClassicDesktopStyleApplicationHandler>(nameof(IClassicDesktopStyleApplicationLifetime));
|
services.AddHandler<ClassicDesktopStyleApplicationHandler>(nameof(IClassicDesktopStyleApplicationLifetime));
|
||||||
services.AddHandler<SingleViewApplicationHandler>(nameof(ISingleViewApplicationLifetime));
|
services.AddHandler<SingleViewApplicationHandler>(nameof(ISingleViewApplicationLifetime));
|
||||||
services.AddHandler<ContentControlHandler>(nameof(ContentControl));
|
services.AddHandler<ContentControlHandler>(nameof(ContentControl));
|
||||||
|
|
||||||
services.AddHandler<FrameHandler>(nameof(Frame));
|
services.AddHandler<FrameHandler>(nameof(Frame));
|
||||||
|
services.TryAddSingleton<ITransientNavigationStore<Frame>, TransientNavigationStore<Frame>>();
|
||||||
|
|
||||||
services.AddHandler<ContentDialogHandler>(nameof(ContentDialog));
|
services.AddHandler<ContentDialogHandler>(nameof(ContentDialog));
|
||||||
services.AddHandler<TaskDialogHandler>(nameof(TaskDialog));
|
services.AddHandler<TaskDialogHandler>(nameof(TaskDialog));
|
||||||
|
|
||||||
@@ -66,7 +69,11 @@ public static class IServiceCollectionExtensions
|
|||||||
services.AddHandler<SelectFilesHandler>();
|
services.AddHandler<SelectFilesHandler>();
|
||||||
|
|
||||||
services.AddHandler<ContentControlHandler>(nameof(ContentControl));
|
services.AddHandler<ContentControlHandler>(nameof(ContentControl));
|
||||||
|
|
||||||
services.AddHandler<FrameHandler>(nameof(Frame));
|
services.AddHandler<FrameHandler>(nameof(Frame));
|
||||||
|
|
||||||
|
services.TryAddSingleton(provider.GetRequiredService<ITransientNavigationStore<Frame>>());
|
||||||
|
|
||||||
services.AddHandler<ContentDialogHandler>(nameof(ContentDialog));
|
services.AddHandler<ContentDialogHandler>(nameof(ContentDialog));
|
||||||
services.AddHandler<TaskDialogHandler>(nameof(TaskDialog));
|
services.AddHandler<TaskDialogHandler>(nameof(TaskDialog));
|
||||||
})));
|
})));
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
namespace Toolkit.Avalonia;
|
||||||
|
|
||||||
|
public interface ITransientNavigationStore<TControl>
|
||||||
|
where TControl : class
|
||||||
|
{
|
||||||
|
void Clear();
|
||||||
|
|
||||||
|
T? Get<T>(TControl control)
|
||||||
|
where T : class;
|
||||||
|
|
||||||
|
void Remove(TControl control);
|
||||||
|
|
||||||
|
void Set(TControl control,
|
||||||
|
object parameters);
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
namespace Toolkit.Avalonia;
|
||||||
|
|
||||||
|
public class TransientNavigationStore<TControl> : ITransientNavigationStore<TControl>
|
||||||
|
where TControl : class
|
||||||
|
{
|
||||||
|
private readonly Dictionary<TControl, Dictionary<Type, object>> controlDataMap = [];
|
||||||
|
|
||||||
|
public void Set(TControl control,
|
||||||
|
object parameters)
|
||||||
|
{
|
||||||
|
if (!controlDataMap.TryGetValue(control, out var typeMap))
|
||||||
|
{
|
||||||
|
typeMap = new Dictionary<Type, object>();
|
||||||
|
controlDataMap[control] = typeMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
typeMap[parameters.GetType()] = parameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T? Get<T>(TControl control)
|
||||||
|
where T : class
|
||||||
|
{
|
||||||
|
if (controlDataMap.TryGetValue(control, out var typeMap) &&
|
||||||
|
typeMap.TryGetValue(typeof(T), out var parameters))
|
||||||
|
{
|
||||||
|
typeMap.Remove(typeof(T));
|
||||||
|
return parameters as T;
|
||||||
|
}
|
||||||
|
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Remove(TControl control) => controlDataMap.Remove(control);
|
||||||
|
|
||||||
|
public void Clear() => controlDataMap.Clear();
|
||||||
|
}
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
namespace Toolkit.Foundation;
|
namespace Toolkit.Foundation;
|
||||||
|
|
||||||
public class ContentFactory(IServiceProvider provider,
|
public class ContentFactory(IServiceProvider provider,
|
||||||
IServiceFactory factory) : IContentFactory
|
IServiceFactory factory) :
|
||||||
|
IContentFactory
|
||||||
{
|
{
|
||||||
public Task<object?> CreateAsync(IContentTemplateDescriptor descriptor,
|
public object? Create(IContentTemplateDescriptor descriptor,
|
||||||
object[] parameters)
|
object[] parameters)
|
||||||
{
|
{
|
||||||
object? content = parameters is { Length: > 0 }
|
object? content = parameters is { Length: > 0 }
|
||||||
@@ -22,6 +23,6 @@ public class ContentFactory(IServiceProvider provider,
|
|||||||
}
|
}
|
||||||
}, descriptor.Key);
|
}, descriptor.Key);
|
||||||
|
|
||||||
return Task.FromResult<object?>(content);
|
return content;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
{
|
{
|
||||||
public interface IContentFactory
|
public interface IContentFactory
|
||||||
{
|
{
|
||||||
Task<object?> CreateAsync(IContentTemplateDescriptor descriptor,
|
object? Create(IContentTemplateDescriptor descriptor,
|
||||||
object[] resolvedArguments);
|
object[] parameters);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
namespace Toolkit.Foundation;
|
|
||||||
|
|
||||||
public interface IKeepAlive;
|
|
||||||
@@ -62,7 +62,7 @@ public class Navigation(IServiceProvider provider,
|
|||||||
|
|
||||||
if (region is not null)
|
if (region is not null)
|
||||||
{
|
{
|
||||||
object? content = await contentFactory.CreateAsync(descriptor, resolvedArguments);
|
object? content = contentFactory.Create(descriptor, resolvedArguments);
|
||||||
if (content is not null)
|
if (content is not null)
|
||||||
{
|
{
|
||||||
Type navigationType = region is Type type ? type : region.GetType();
|
Type navigationType = region is Type type ? type : region.GetType();
|
||||||
|
|||||||
@@ -46,6 +46,8 @@ public partial class ObservableCollection<TViewModel> :
|
|||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
private int count;
|
private int count;
|
||||||
|
|
||||||
|
private Func<TViewModel>? defaultSelectionFactory;
|
||||||
|
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
private bool isActivated;
|
private bool isActivated;
|
||||||
|
|
||||||
@@ -145,86 +147,27 @@ public partial class ObservableCollection<TViewModel> :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Func<TViewModel>? defaultSelectionFactory;
|
public void Activate(Func<ActivationBuilder> activateDelegate,
|
||||||
|
bool reset = false)
|
||||||
public void SetSource(IList<TViewModel> source,
|
|
||||||
Func<TViewModel>? defaultSelectionFactory)
|
|
||||||
{
|
{
|
||||||
foreach (TViewModel item in source)
|
if (reset)
|
||||||
{
|
{
|
||||||
Add(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (defaultSelectionFactory is not null)
|
|
||||||
{
|
|
||||||
this.defaultSelectionFactory = defaultSelectionFactory;
|
|
||||||
SelectedItem = defaultSelectionFactory.Invoke();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (source is INotifyCollectionChanged observableSource)
|
|
||||||
{
|
|
||||||
observableSource.CollectionChanged -= SourceCollectionChanged;
|
|
||||||
observableSource.CollectionChanged += SourceCollectionChanged;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SourceCollectionChanged(object? sender,
|
|
||||||
NotifyCollectionChangedEventArgs args)
|
|
||||||
{
|
|
||||||
switch (args.Action)
|
|
||||||
{
|
|
||||||
case NotifyCollectionChangedAction.Add:
|
|
||||||
if (args.NewItems is not null)
|
|
||||||
{
|
|
||||||
foreach (TViewModel newItem in args.NewItems)
|
|
||||||
{
|
|
||||||
Add(newItem);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case NotifyCollectionChangedAction.Remove:
|
|
||||||
if (args.OldItems is not null)
|
|
||||||
{
|
|
||||||
foreach (TViewModel oldItem in args.OldItems)
|
|
||||||
{
|
|
||||||
if (this.FirstOrDefault(x => x.Equals(oldItem)) is TViewModel removedItem)
|
|
||||||
{
|
|
||||||
Remove(removedItem);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case NotifyCollectionChangedAction.Reset:
|
|
||||||
|
|
||||||
Clear();
|
Clear();
|
||||||
if (sender is IEnumerable<TViewModel> collection)
|
|
||||||
{
|
|
||||||
foreach (TViewModel item in collection)
|
|
||||||
{
|
|
||||||
Add(item);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (defaultSelectionFactory is not null)
|
ActivationBuilder builder = activateDelegate.Invoke();
|
||||||
{
|
Publisher.Publish(builder.Value, builder.Key);
|
||||||
SelectedItem = defaultSelectionFactory.Invoke();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual Task OnActivated()
|
public void Activate(bool reset = false)
|
||||||
{
|
{
|
||||||
IsActivated = true;
|
if (reset)
|
||||||
while (pendingEvents.Count > 0)
|
|
||||||
{
|
{
|
||||||
object current = pendingEvents.Dequeue();
|
Clear();
|
||||||
Handle((dynamic)current);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return Task.CompletedTask;
|
ActivationBuilder builder = ActivationBuilder();
|
||||||
|
Publisher.PublishUI(builder.Value, builder.Key);
|
||||||
}
|
}
|
||||||
|
|
||||||
public TViewModel Add<T>(params object?[] parameters)
|
public TViewModel Add<T>(params object?[] parameters)
|
||||||
@@ -285,14 +228,6 @@ public partial class ObservableCollection<TViewModel> :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Reset(Action<ObservableCollection<TViewModel>> factory, bool disposeItems = true)
|
|
||||||
{
|
|
||||||
SelectedItem = default;
|
|
||||||
|
|
||||||
Clear(disposeItems);
|
|
||||||
factory.Invoke(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Clear(bool disposeItems = false)
|
public void Clear(bool disposeItems = false)
|
||||||
{
|
{
|
||||||
isClearing = true;
|
isClearing = true;
|
||||||
@@ -342,33 +277,12 @@ public partial class ObservableCollection<TViewModel> :
|
|||||||
void ICollection.CopyTo(Array array, int index) =>
|
void ICollection.CopyTo(Array array, int index) =>
|
||||||
collection.CopyTo((TViewModel[])array, index);
|
collection.CopyTo((TViewModel[])array, index);
|
||||||
|
|
||||||
public virtual Task OnDeactivated()
|
|
||||||
{
|
|
||||||
IsActivated = false;
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual Task OnDeactivating() =>
|
|
||||||
Task.CompletedTask;
|
|
||||||
|
|
||||||
public virtual void Dispose()
|
public virtual void Dispose()
|
||||||
{
|
{
|
||||||
GC.SuppressFinalize(this);
|
GC.SuppressFinalize(this);
|
||||||
Disposer.Dispose(this);
|
Disposer.Dispose(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Activate(Func<ActivationBuilder> activateDelegate,
|
|
||||||
bool reset = false)
|
|
||||||
{
|
|
||||||
if (reset)
|
|
||||||
{
|
|
||||||
Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
ActivationBuilder builder = activateDelegate.Invoke();
|
|
||||||
Publisher.Publish(builder.Value, builder.Key);
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerator<TViewModel> GetEnumerator() =>
|
public IEnumerator<TViewModel> GetEnumerator() =>
|
||||||
collection.GetEnumerator();
|
collection.GetEnumerator();
|
||||||
|
|
||||||
@@ -505,10 +419,6 @@ public partial class ObservableCollection<TViewModel> :
|
|||||||
IsCompatibleObject(value) ?
|
IsCompatibleObject(value) ?
|
||||||
IndexOf((TViewModel)value!) : -1;
|
IndexOf((TViewModel)value!) : -1;
|
||||||
|
|
||||||
public virtual void OnInitialize()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
[RelayCommand]
|
[RelayCommand]
|
||||||
public virtual void Initialize()
|
public virtual void Initialize()
|
||||||
{
|
{
|
||||||
@@ -519,37 +429,12 @@ public partial class ObservableCollection<TViewModel> :
|
|||||||
|
|
||||||
IsInitialized = true;
|
IsInitialized = true;
|
||||||
Subscriber.Subscribe(this);
|
Subscriber.Subscribe(this);
|
||||||
|
|
||||||
OnInitialize();
|
OnInitialize();
|
||||||
|
|
||||||
Activate();
|
Activate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Replace<T>(int index,
|
|
||||||
params object?[] parameters)
|
|
||||||
where T :
|
|
||||||
TViewModel
|
|
||||||
{
|
|
||||||
if (index <= Count - 1)
|
|
||||||
{
|
|
||||||
RemoveItem(index);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
index = Count;
|
|
||||||
}
|
|
||||||
|
|
||||||
T? item = Factory.Create<T>(args =>
|
|
||||||
{
|
|
||||||
if (args is IInitialization initialization)
|
|
||||||
{
|
|
||||||
initialization.Initialize();
|
|
||||||
}
|
|
||||||
}, parameters);
|
|
||||||
|
|
||||||
Insert(index, item);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public TViewModel Insert<T>(int index = 0,
|
public TViewModel Insert<T>(int index = 0,
|
||||||
params object?[] parameters)
|
params object?[] parameters)
|
||||||
where T :
|
where T :
|
||||||
@@ -634,6 +519,31 @@ public partial class ObservableCollection<TViewModel> :
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public virtual Task OnActivated()
|
||||||
|
{
|
||||||
|
IsActivated = true;
|
||||||
|
while (pendingEvents.Count > 0)
|
||||||
|
{
|
||||||
|
object current = pendingEvents.Dequeue();
|
||||||
|
Handle((dynamic)current);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual Task OnDeactivated()
|
||||||
|
{
|
||||||
|
IsActivated = false;
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual Task OnDeactivating() =>
|
||||||
|
Task.CompletedTask;
|
||||||
|
|
||||||
|
public virtual void OnInitialize()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
public bool Remove(TViewModel item)
|
public bool Remove(TViewModel item)
|
||||||
{
|
{
|
||||||
int index = collection.IndexOf(item);
|
int index = collection.IndexOf(item);
|
||||||
@@ -669,6 +579,32 @@ public partial class ObservableCollection<TViewModel> :
|
|||||||
public void RemoveAt(int index) =>
|
public void RemoveAt(int index) =>
|
||||||
RemoveItem(index);
|
RemoveItem(index);
|
||||||
|
|
||||||
|
public bool Replace<T>(int index,
|
||||||
|
params object?[] parameters)
|
||||||
|
where T :
|
||||||
|
TViewModel
|
||||||
|
{
|
||||||
|
if (index <= Count - 1)
|
||||||
|
{
|
||||||
|
RemoveItem(index);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
index = Count;
|
||||||
|
}
|
||||||
|
|
||||||
|
T? item = Factory.Create<T>(args =>
|
||||||
|
{
|
||||||
|
if (args is IInitialization initialization)
|
||||||
|
{
|
||||||
|
initialization.Initialize();
|
||||||
|
}
|
||||||
|
}, parameters);
|
||||||
|
|
||||||
|
Insert(index, item);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public bool Replace(int index,
|
public bool Replace(int index,
|
||||||
TViewModel item)
|
TViewModel item)
|
||||||
{
|
{
|
||||||
@@ -685,6 +621,14 @@ public partial class ObservableCollection<TViewModel> :
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Reset(Action<ObservableCollection<TViewModel>> factory, bool disposeItems = true)
|
||||||
|
{
|
||||||
|
SelectedItem = default;
|
||||||
|
|
||||||
|
Clear(disposeItems);
|
||||||
|
factory.Invoke(this);
|
||||||
|
}
|
||||||
|
|
||||||
public void Revert()
|
public void Revert()
|
||||||
{
|
{
|
||||||
foreach (object trackedProperty in trackedProperties.Values)
|
foreach (object trackedProperty in trackedProperties.Values)
|
||||||
@@ -693,15 +637,24 @@ public partial class ObservableCollection<TViewModel> :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Activate(bool reset = false)
|
public void SetSource(IList<TViewModel> source, Func<TViewModel>? defaultSelectionFactory)
|
||||||
{
|
{
|
||||||
if (reset)
|
foreach (TViewModel item in source)
|
||||||
{
|
{
|
||||||
Clear();
|
Add(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
ActivationBuilder builder = ActivationBuilder();
|
if (defaultSelectionFactory is not null)
|
||||||
Publisher.PublishUI(builder.Value, builder.Key);
|
{
|
||||||
|
this.defaultSelectionFactory = defaultSelectionFactory;
|
||||||
|
SelectedItem = defaultSelectionFactory.Invoke();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (source is INotifyCollectionChanged observableSource)
|
||||||
|
{
|
||||||
|
observableSource.CollectionChanged -= SourceCollectionChanged;
|
||||||
|
observableSource.CollectionChanged += SourceCollectionChanged;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Track<T>(string propertyName, Func<T> getter, Action<T> setter)
|
public void Track<T>(string propertyName, Func<T> getter, Action<T> setter)
|
||||||
@@ -725,7 +678,7 @@ public partial class ObservableCollection<TViewModel> :
|
|||||||
Disposer.Add(this, item);
|
Disposer.Add(this, item);
|
||||||
Disposer.Add(item, Disposable.Create(() =>
|
Disposer.Add(item, Disposable.Create(() =>
|
||||||
{
|
{
|
||||||
if (item is IRemovable && !isClearing)
|
if (item is IDisposable && !isClearing)
|
||||||
{
|
{
|
||||||
if (item is IList collection)
|
if (item is IList collection)
|
||||||
{
|
{
|
||||||
@@ -739,6 +692,10 @@ public partial class ObservableCollection<TViewModel> :
|
|||||||
collection.Insert(index > Count ? Count : index, item);
|
collection.Insert(index > Count ? Count : index, item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected virtual void OnSelectedItemChanged()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
protected virtual void RemoveItem(int index) =>
|
protected virtual void RemoveItem(int index) =>
|
||||||
collection.RemoveAt(index);
|
collection.RemoveAt(index);
|
||||||
|
|
||||||
@@ -782,10 +739,52 @@ public partial class ObservableCollection<TViewModel> :
|
|||||||
OnSelectedItemChanged();
|
OnSelectedItemChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void OnSelectedItemChanged()
|
private void SourceCollectionChanged(object? sender,
|
||||||
|
NotifyCollectionChangedEventArgs args)
|
||||||
{
|
{
|
||||||
|
switch (args.Action)
|
||||||
|
{
|
||||||
|
case NotifyCollectionChangedAction.Add:
|
||||||
|
if (args.NewItems is not null)
|
||||||
|
{
|
||||||
|
foreach (TViewModel newItem in args.NewItems)
|
||||||
|
{
|
||||||
|
Add(newItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NotifyCollectionChangedAction.Remove:
|
||||||
|
if (args.OldItems is not null)
|
||||||
|
{
|
||||||
|
foreach (TViewModel oldItem in args.OldItems)
|
||||||
|
{
|
||||||
|
if (this.FirstOrDefault(x => x.Equals(oldItem)) is TViewModel removedItem)
|
||||||
|
{
|
||||||
|
Remove(removedItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NotifyCollectionChangedAction.Reset:
|
||||||
|
|
||||||
|
Clear();
|
||||||
|
if (sender is IEnumerable<TViewModel> collection)
|
||||||
|
{
|
||||||
|
foreach (TViewModel item in collection)
|
||||||
|
{
|
||||||
|
Add(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (defaultSelectionFactory is not null)
|
||||||
|
{
|
||||||
|
SelectedItem = defaultSelectionFactory.Invoke();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
private void UpdateSelection(TViewModel item)
|
private void UpdateSelection(TViewModel item)
|
||||||
{
|
{
|
||||||
if (item is ISelectable newSelection)
|
if (item is ISelectable newSelection)
|
||||||
|
|||||||
Reference in New Issue
Block a user