This commit is contained in:
Dan Clark
2024-11-19 09:37:18 +00:00
parent 748487031d
commit 71d297b343
10 changed files with 373 additions and 362 deletions
@@ -10,14 +10,18 @@ public class ClassicDesktopStyleApplicationHandler :
{ {
public void Handle(NavigateTemplateEventArgs args) public void Handle(NavigateTemplateEventArgs args)
{ {
if (Application.Current?.ApplicationLifetime is if (Application.Current?.ApplicationLifetime
IClassicDesktopStyleApplicationLifetime lifeTime) is not IClassicDesktopStyleApplicationLifetime lifeTime)
{ {
if (args.Template is Window window) return;
{
lifeTime.MainWindow = window;
window.DataContext = args.Content;
}
} }
if (args.Template is not Window window)
{
return;
}
lifeTime.MainWindow = window;
window.DataContext = args.Content;
} }
} }
+40 -39
View File
@@ -9,50 +9,51 @@ public class ContentControlHandler :
{ {
public void Handle(NavigateTemplateEventArgs args) public void Handle(NavigateTemplateEventArgs args)
{ {
if (args.Region is ContentControl contentControl) if (args.Region is not ContentControl contentControl)
{ {
if (args.Template is Control control) return;
}
if (args.Template is not Control control)
{
return;
}
void HandleLoaded(object? sender, RoutedEventArgs args)
{
control.Loaded -= HandleLoaded;
if (control.DataContext is object content)
{ {
TaskCompletionSource taskCompletionSource = new(); if (content is IActivation activation)
void HandleLoaded(object? sender, RoutedEventArgs args)
{ {
control.Loaded -= HandleLoaded; activation.IsActive = true;
if (control.DataContext is object content)
{
if (content is IActivation activation)
{
activation.IsActive = true;
}
}
taskCompletionSource.SetResult();
} }
void HandleUnloaded(object? sender, RoutedEventArgs args)
{
control.Unloaded -= HandleLoaded;
if (control.DataContext is object content)
{
if (content is IActivation activation)
{
activation.IsActive = false;
}
if (content is IDisposable disposable)
{
disposable.Dispose();
}
}
}
control.Loaded += HandleLoaded;
control.Unloaded += HandleUnloaded;
control.DataContext = args.Content;
contentControl.Content = null;
contentControl.Content = control;
} }
} }
void HandleUnloaded(object? sender, RoutedEventArgs args)
{
control.Unloaded -= HandleLoaded;
if (control.DataContext is object content)
{
if (content is IActivation activation)
{
activation.IsActive = false;
}
if (content is IDisposable disposable)
{
disposable.Dispose();
}
}
}
control.Loaded += HandleLoaded;
control.Unloaded += HandleUnloaded;
control.DataContext = args.Content;
contentControl.Content = null;
contentControl.Content = control;
} }
} }
-3
View File
@@ -114,9 +114,6 @@ public class ContentDialogHandler :
dialog.SecondaryButtonClick += HandleSecondaryButtonClick; dialog.SecondaryButtonClick += HandleSecondaryButtonClick;
await dialog.ShowAsync(); await dialog.ShowAsync();
dialog.PrimaryButtonClick += HandlePrimaryButtonClick;
dialog.SecondaryButtonClick += HandleSecondaryButtonClick;
} }
} }
} }
+161 -156
View File
@@ -13,190 +13,195 @@ public class FrameHandler(ITransientNavigationStore<Frame> navigationStore) :
{ {
public void Handle(NavigateTemplateEventArgs args) public void Handle(NavigateTemplateEventArgs args)
{ {
if (args.Region is Frame frame) if (args.Region is not Frame frame)
{ {
frame.NavigationPageFactory ??= new NavigationPageFactory(); return;
if (args.Template is Control control) }
if (args.Template is not Control control)
{
return;
}
frame.NavigationPageFactory ??= new NavigationPageFactory();
void Navigated(Control sender)
{
void HandleNavigatedTo(object? _, NavigationEventArgs __)
{ {
void Navigated(Control sender) async void HandleNavigatingFrom(object? _, NavigatingCancelEventArgs args)
{ {
void HandleNavigatedTo(object? _, NavigationEventArgs __) sender.RemoveHandler(Frame.NavigatingFromEvent, HandleNavigatingFrom);
control.Unloaded -= HandleUnloaded;
void HandleNavigatedFrom(object? _, NavigationEventArgs args)
{ {
async void HandleNavigatingFrom(object? _, NavigatingCancelEventArgs args) sender.RemoveHandler(Frame.NavigatedFromEvent, HandleNavigatedFrom);
{
sender.RemoveHandler(Frame.NavigatingFromEvent, HandleNavigatingFrom);
control.Unloaded -= HandleUnloaded;
void HandleNavigatedFrom(object? _, NavigationEventArgs args)
{
sender.RemoveHandler(Frame.NavigatedFromEvent, HandleNavigatedFrom);
if (sender.DataContext is object content)
{
if (content is IActivation activation)
{
activation.IsActive = false;
}
if (content is IDisposable disposable)
{
FrameNavigationOptions? options = navigationStore.Get<FrameNavigationOptions>(frame);
if (options is not FrameNavigationOptions frameOptions ||
!frameOptions.IsNavigationStackEnabled)
{
disposable.Dispose();
}
}
}
}
sender.AddHandler(Frame.NavigatedFromEvent, HandleNavigatedFrom);
if (sender.DataContext is object content)
{
if (content is IConfirmation confirmation &&
!await confirmation.Confirm())
{
args.Cancel = true;
}
}
}
sender.AddHandler(Frame.NavigatingFromEvent, HandleNavigatingFrom);
if (sender.DataContext is object content) if (sender.DataContext is object content)
{ {
if (content is IActivation activation) if (content is IActivation activation)
{ {
activation.IsActive = true; activation.IsActive = false;
} }
}
void HandleUnloaded(object? _, RoutedEventArgs __) if (content is IDisposable disposable)
{
sender.RemoveHandler(Frame.NavigatedToEvent, HandleNavigatedTo);
sender.RemoveHandler(Frame.NavigatingFromEvent, HandleNavigatingFrom);
control.Unloaded -= HandleUnloaded;
if (control.DataContext is object content)
{ {
if (content is IActivation activation) FrameNavigationOptions? options = navigationStore.Get<FrameNavigationOptions>(frame);
{ if (options is not FrameNavigationOptions frameOptions ||
activation.IsActive = true; !frameOptions.IsNavigationStackEnabled)
}
if (content is IDisposable disposable)
{ {
disposable.Dispose(); disposable.Dispose();
} }
} }
} }
sender.Unloaded += HandleUnloaded;
} }
sender.AddHandler(Frame.NavigatedToEvent, HandleNavigatedTo); sender.AddHandler(Frame.NavigatedFromEvent, HandleNavigatedFrom);
}
control.DataContext = args.Content; if (sender.DataContext is object content)
FrameNavigationOptions navigationOptions = new();
List<Action> postNavigateActions = [];
void CleanUp(int start, int end)
{
int startIndex = Math.Max(0, start - 1);
int endIndex = Math.Min(frame.BackStack.Count - 1, end - 1);
for (int i = endIndex; i >= startIndex; i--)
{ {
PageStackEntry? entry = frame.BackStack[i]; if (content is IConfirmation confirmation &&
if (entry.Context is Control control) !await confirmation.Confirm())
{ {
if (control.DataContext is IDisposable disposable) args.Cancel = true;
{
disposable.Dispose();
}
}
frame.BackStack.RemoveAt(i);
}
}
if (args.Parameters is not null)
{
if (args.Parameters.TryGetValue("Transition", out object? transition))
{
switch ($"{transition}")
{
case "Suppress":
navigationOptions.TransitionInfoOverride = new SuppressNavigationTransitionInfo();
break;
case "FromLeft":
case "FromRight":
case "FromTop":
case "FromBottom":
navigationOptions.TransitionInfoOverride = new SlideNavigationTransitionInfo
{
Effect = Enum.Parse<SlideNavigationTransitionEffect>($"{transition}")
};
break;
}
}
if (args.Parameters.TryGetValue("IsBackStackEnabled", out object? isBackStackEnabled))
{
if (isBackStackEnabled is bool value)
{
navigationOptions.IsNavigationStackEnabled = value;
}
}
if (args.Parameters.TryGetValue("ClearBackStack", out object? clearBackStack))
{
if (clearBackStack is bool clearBool)
{
if (clearBool)
{
postNavigateActions.Add(() => CleanUp(1, frame.BackStack.Count));
}
}
if (clearBackStack is string clearString)
{
if (clearString.StartsWith('[') && clearString.EndsWith(']') && clearString.Contains('-'))
{
string range = clearString.Trim('[', ']');
string[] parts = range.Split('-');
if (parts.Length == 2 && int.TryParse(parts[0], out int start) &&
int.TryParse(parts[1], out int end))
{
postNavigateActions.Add(() => CleanUp(start, end));
}
else
{
postNavigateActions.Add(() => CleanUp(1, frame.BackStack.Count));
}
}
else
{
postNavigateActions.Add(() => CleanUp(1, frame.BackStack.Count));
}
} }
} }
} }
Navigated(control); sender.AddHandler(Frame.NavigatingFromEvent, HandleNavigatingFrom);
if (sender.DataContext is object content)
navigationStore.Set(frame, navigationOptions);
frame.NavigateFromObject(control, navigationOptions);
foreach (Action postAction in postNavigateActions)
{ {
postAction.Invoke(); if (content is IActivation activation)
{
activation.IsActive = true;
}
}
void HandleUnloaded(object? _, RoutedEventArgs __)
{
sender.RemoveHandler(Frame.NavigatedToEvent, HandleNavigatedTo);
sender.RemoveHandler(Frame.NavigatingFromEvent, HandleNavigatingFrom);
control.Unloaded -= HandleUnloaded;
if (control.DataContext is object content)
{
if (content is IActivation activation)
{
activation.IsActive = true;
}
if (content is IDisposable disposable)
{
disposable.Dispose();
}
}
}
sender.Unloaded += HandleUnloaded;
}
sender.AddHandler(Frame.NavigatedToEvent, HandleNavigatedTo);
}
control.DataContext = args.Content;
FrameNavigationOptions navigationOptions = new();
List<Action> postNavigateActions = [];
void CleanUp(int start, int end)
{
int startIndex = Math.Max(0, start - 1);
int endIndex = Math.Min(frame.BackStack.Count - 1, end - 1);
for (int i = endIndex; i >= startIndex; i--)
{
PageStackEntry? entry = frame.BackStack[i];
if (entry.Context is Control control)
{
if (control.DataContext is IDisposable disposable)
{
disposable.Dispose();
}
}
frame.BackStack.RemoveAt(i);
}
}
if (args.Parameters is not null)
{
if (args.Parameters.TryGetValue("Transition", out object? transition))
{
switch ($"{transition}")
{
case "Suppress":
navigationOptions.TransitionInfoOverride = new SuppressNavigationTransitionInfo();
break;
case "FromLeft":
case "FromRight":
case "FromTop":
case "FromBottom":
navigationOptions.TransitionInfoOverride = new SlideNavigationTransitionInfo
{
Effect = Enum.Parse<SlideNavigationTransitionEffect>($"{transition}")
};
break;
} }
} }
if (args.Parameters.TryGetValue("IsBackStackEnabled", out object? isBackStackEnabled))
{
if (isBackStackEnabled is bool value)
{
navigationOptions.IsNavigationStackEnabled = value;
}
}
if (args.Parameters.TryGetValue("ClearBackStack", out object? clearBackStack))
{
if (clearBackStack is bool clearBool)
{
if (clearBool)
{
postNavigateActions.Add(() => CleanUp(1, frame.BackStack.Count));
}
}
if (clearBackStack is string clearString)
{
if (clearString.StartsWith('[') && clearString.EndsWith(']') && clearString.Contains('-'))
{
string range = clearString.Trim('[', ']');
string[] parts = range.Split('-');
if (parts.Length == 2 && int.TryParse(parts[0], out int start) &&
int.TryParse(parts[1], out int end))
{
postNavigateActions.Add(() => CleanUp(start, end));
}
else
{
postNavigateActions.Add(() => CleanUp(1, frame.BackStack.Count));
}
}
else
{
postNavigateActions.Add(() => CleanUp(1, frame.BackStack.Count));
}
}
}
}
Navigated(control);
navigationStore.Set(frame, navigationOptions);
frame.NavigateFromObject(control, navigationOptions);
foreach (Action postAction in postNavigateActions)
{
postAction.Invoke();
} }
} }
-7
View File
@@ -6,10 +6,3 @@ public record NavigateEventArgs(string Route,
object? Sender = null, object? Sender = null,
EventHandler? Navigated = null, EventHandler? Navigated = null,
IDictionary<string, object>? Parameters = null); IDictionary<string, object>? Parameters = null);
public record NavigateTemplateEventArgs(object Region,
object Template,
object Content,
object? Sender = null,
IDictionary<string, object>? Parameters = null);
@@ -0,0 +1,7 @@
namespace Toolkit.Foundation;
public record NavigateTemplateEventArgs(object Region,
object Template,
object Content,
object? Sender = null,
IDictionary<string, object>? Parameters = null);
+2 -5
View File
@@ -37,8 +37,7 @@ public class Navigation(IServiceProvider provider,
.GetConstructors() .GetConstructors()
.FirstOrDefault()? .FirstOrDefault()?
.GetParameters() .GetParameters()
.Select(x => .Select(x => x?.Name is not null && arguments is not null && arguments.TryGetValue(x.Name, out object? argument)
x?.Name is not null && arguments is not null && arguments.TryGetValue(x.Name, out object? argument)
? argument ? argument
: null) : null)
.Where(argument => argument is not null) .Where(argument => argument is not null)
@@ -70,9 +69,7 @@ public class Navigation(IServiceProvider provider,
object? content = contentFactory.Create(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(); messenger.Send(new NavigateTemplateEventArgs(region, template, content, sender, parameters), region is string ? $"{region}" : region.GetType().Name);
messenger.Send(new NavigateTemplateEventArgs(region, template, content, sender, parameters), navigationType.Name);
if (currentSegmentIndex == segmentCount) if (currentSegmentIndex == segmentCount)
{ {
navigated?.Invoke(this, EventArgs.Empty); navigated?.Invoke(this, EventArgs.Empty);
+1 -1
View File
@@ -75,7 +75,7 @@ public class NavigateAction :
ImmutableDictionary<string, object>.Empty; ImmutableDictionary<string, object>.Empty;
observableViewModel.Messenger.Send(new NavigateEventArgs(Route, Region.Equals(this) ? content : Region, Scope ?? null, observableViewModel.Messenger.Send(new NavigateEventArgs(Route, Region.Equals(this) ? content : Region, Scope ?? null,
content.DataContext, Navigated, parameters)); content, Navigated, parameters));
} }
} }
+38 -39
View File
@@ -9,50 +9,49 @@ public class ContentControlHandler :
{ {
public void Handle(NavigateTemplateEventArgs args) public void Handle(NavigateTemplateEventArgs args)
{ {
if (args.Region is ContentControl contentControl) if (args.Region is not ContentControl contentControl)
{ {
if (args.Template is Control control) return;
}
if (args.Template is not Control control)
{
return;
}
void HandleLoaded(object? sender, RoutedEventArgs args)
{
control.Loaded -= HandleLoaded;
if (control.DataContext is object content)
{ {
TaskCompletionSource taskCompletionSource = new(); if (content is IActivation activation)
void HandleLoaded(object? sender, RoutedEventArgs args)
{ {
control.Loaded -= HandleLoaded; activation.IsActive = true;
if (control.DataContext is object content)
{
if (content is IActivation activation)
{
activation.IsActive = true;
}
}
taskCompletionSource.SetResult();
} }
void HandleUnloaded(object? sender, RoutedEventArgs args)
{
control.Unloaded -= HandleLoaded;
if (control.DataContext is object content)
{
if (content is IActivation activation)
{
activation.IsActive = false;
}
if (content is IDisposable disposable)
{
disposable.Dispose();
}
}
}
control.Loaded += HandleLoaded;
control.Unloaded += HandleUnloaded;
control.DataContext = args.Content;
contentControl.Content = null;
contentControl.Content = control;
} }
} }
void HandleUnloaded(object? sender, RoutedEventArgs args)
{
control.Unloaded -= HandleLoaded;
if (control.DataContext is object content)
{
if (content is IActivation activation)
{
activation.IsActive = false;
}
if (content is IDisposable disposable)
{
disposable.Dispose();
}
}
}
control.Loaded += HandleLoaded;
control.Unloaded += HandleUnloaded;
control.DataContext = args.Content;
contentControl.Content = control;
} }
} }
+113 -105
View File
@@ -1,4 +1,5 @@
using Microsoft.UI.Xaml.Controls; using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Toolkit.Foundation; using Toolkit.Foundation;
namespace Toolkit.WinUI; namespace Toolkit.WinUI;
@@ -8,111 +9,118 @@ public class ContentDialogHandler :
{ {
public async void Handle(NavigateTemplateEventArgs args) public async void Handle(NavigateTemplateEventArgs args)
{ {
if (args.Template is ContentDialog dialog) if (args.Template is not ContentDialog dialog)
{ {
dialog.DataContext = args.Content; return;
async void HandlePrimaryButtonClick(ContentDialog sender,
ContentDialogButtonClickEventArgs args)
{
dialog.PrimaryButtonClick -= HandlePrimaryButtonClick;
if (dialog.DataContext is object content)
{
if (content is IPrimaryConfirmation primaryConfirmation)
{
ContentDialogButtonClickDeferral deferral = args.GetDeferral();
if (!await primaryConfirmation.ConfirmPrimary())
{
args.Cancel = true;
dialog.PrimaryButtonClick += HandlePrimaryButtonClick;
}
deferral.Complete();
}
}
}
async void HandleSecondaryButtonClick(ContentDialog sender,
ContentDialogButtonClickEventArgs args)
{
dialog.SecondaryButtonClick -= HandleSecondaryButtonClick;
if (dialog.DataContext is object content)
{
if (content is ISecondaryConfirmation secondaryConfirmation)
{
ContentDialogButtonClickDeferral deferral = args.GetDeferral();
if (!await secondaryConfirmation.ConfirmSecondary())
{
args.Cancel = true;
dialog.SecondaryButtonClick += HandleSecondaryButtonClick;
}
deferral.Complete();
}
}
}
async void HandleClosing(ContentDialog sender,
ContentDialogClosingEventArgs args)
{
if (args.Result is ContentDialogResult.Primary ||
args.Result is ContentDialogResult.Secondary)
{
dialog.Closing -= HandleClosing;
if (dialog.DataContext is object content)
{
if (content is IConfirmation confirmation)
{
ContentDialogClosingDeferral deferral = args.GetDeferral();
if (!await confirmation.Confirm())
{
args.Cancel = true;
dialog.Closing += HandleClosing;
}
deferral.Complete();
}
}
}
}
void HandleOpened(ContentDialog sender,
ContentDialogOpenedEventArgs args)
{
dialog.Opened -= HandleOpened;
if (dialog.DataContext is object content)
{
if (content is IActivation activation)
{
activation.IsActive = true;
}
}
}
void HandleClosed(ContentDialog sender,
ContentDialogClosedEventArgs args)
{
dialog.Closed -= HandleClosed;
if (dialog.DataContext is object content)
{
if (content is IActivation activation)
{
activation.IsActive = false;
}
}
}
dialog.Opened += HandleOpened;
dialog.Closing += HandleClosing;
dialog.Closed += HandleClosed;
dialog.PrimaryButtonClick += HandlePrimaryButtonClick;
dialog.SecondaryButtonClick += HandleSecondaryButtonClick;
await dialog.ShowAsync();
dialog.PrimaryButtonClick += HandlePrimaryButtonClick;
dialog.SecondaryButtonClick += HandleSecondaryButtonClick;
} }
if (args.Sender is not Control parent)
{
return;
}
dialog.XamlRoot = parent.XamlRoot;
dialog.Style = Application.Current.Resources["DefaultContentDialogStyle"] as Style;
dialog.DataContext = args.Content;
async void HandlePrimaryButtonClick(ContentDialog sender,
ContentDialogButtonClickEventArgs args)
{
dialog.PrimaryButtonClick -= HandlePrimaryButtonClick;
if (dialog.DataContext is object content)
{
if (content is IPrimaryConfirmation primaryConfirmation)
{
ContentDialogButtonClickDeferral deferral = args.GetDeferral();
if (!await primaryConfirmation.ConfirmPrimary())
{
args.Cancel = true;
dialog.PrimaryButtonClick += HandlePrimaryButtonClick;
}
deferral.Complete();
}
}
}
async void HandleSecondaryButtonClick(ContentDialog sender,
ContentDialogButtonClickEventArgs args)
{
dialog.SecondaryButtonClick -= HandleSecondaryButtonClick;
if (dialog.DataContext is object content)
{
if (content is ISecondaryConfirmation secondaryConfirmation)
{
ContentDialogButtonClickDeferral deferral = args.GetDeferral();
if (!await secondaryConfirmation.ConfirmSecondary())
{
args.Cancel = true;
dialog.SecondaryButtonClick += HandleSecondaryButtonClick;
}
deferral.Complete();
}
}
}
async void HandleClosing(ContentDialog sender,
ContentDialogClosingEventArgs args)
{
if (args.Result is ContentDialogResult.Primary ||
args.Result is ContentDialogResult.Secondary)
{
dialog.Closing -= HandleClosing;
if (dialog.DataContext is object content)
{
if (content is IConfirmation confirmation)
{
ContentDialogClosingDeferral deferral = args.GetDeferral();
if (!await confirmation.Confirm())
{
args.Cancel = true;
dialog.Closing += HandleClosing;
}
deferral.Complete();
}
}
}
}
void HandleOpened(ContentDialog sender,
ContentDialogOpenedEventArgs args)
{
dialog.Opened -= HandleOpened;
if (dialog.DataContext is object content)
{
if (content is IActivation activation)
{
activation.IsActive = true;
}
}
}
void HandleClosed(ContentDialog sender,
ContentDialogClosedEventArgs args)
{
dialog.Closed -= HandleClosed;
if (dialog.DataContext is object content)
{
if (content is IActivation activation)
{
activation.IsActive = false;
}
}
}
dialog.Opened += HandleOpened;
dialog.Closing += HandleClosing;
dialog.Closed += HandleClosed;
dialog.PrimaryButtonClick += HandlePrimaryButtonClick;
dialog.SecondaryButtonClick += HandleSecondaryButtonClick;
await dialog.ShowAsync();
} }
} }