Skip to content

Commit 173949b

Browse files
committed
Enhances XAML Navigation and Dialog Features
Adds attached properties for tabbed page navigation and appearance. Introduces the ability to specify navigation types when going back. Adds logging for navigation failures and provides a way to add services required by markup extensions to prevent runtime errors.
1 parent ca513f0 commit 173949b

File tree

8 files changed

+206
-21
lines changed

8 files changed

+206
-21
lines changed

src/Maui/Prism.Maui/Dialogs/Xaml/ShowDialogExtension.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using System.Windows.Input;
1+
using System.Windows.Input;
22
using Microsoft.Extensions.Logging;
33
using Prism.Ioc;
44
using Prism.Navigation.Xaml;
@@ -7,6 +7,7 @@
77
namespace Prism.Dialogs.Xaml;
88

99
[ContentProperty(nameof(Name))]
10+
[RequireService([typeof(IProvideValueTarget)])]
1011
public class ShowDialogExtension : TargetAwareExtensionBase<ICommand>, ICommand
1112
{
1213
public static readonly BindableProperty NameProperty =

src/Maui/Prism.Maui/Navigation/Regions/Xaml/RegionManager.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ namespace Prism.Navigation.Regions.Xaml;
1414
/// </summary>
1515
public static class RegionManager
1616
{
17-
private static readonly WeakDelegatesManager updatingRegionsListeners = new WeakDelegatesManager();
17+
private static readonly WeakDelegatesManager updatingRegionsListeners = new ();
1818

1919
private static readonly BindableProperty ObservableRegionProperty =
2020
BindableProperty.CreateAttached("ObservableRegion", typeof(ObservableObject<IRegion>), typeof(RegionManager), null);

src/Maui/Prism.Maui/Navigation/Xaml/GoBackExtension.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-

1+
22
namespace Prism.Navigation.Xaml;
33

44
[ContentProperty(nameof(GoBackType))]
5-
public class GoBackExtension : NavigationExtensionBase
5+
[RequireService([typeof(IProvideValueTarget)])]
6+
public partial class GoBackExtension : NavigationExtensionBase
67
{
78
public static readonly BindableProperty GoBackTypeProperty =
89
BindableProperty.Create(nameof(GoBackType), typeof(GoBackType), typeof(GoBackExtension), GoBackType.Default);
Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,17 @@
1-

21
namespace Prism.Navigation.Xaml;
32

3+
/// <summary>
4+
/// Specifies the type of navigation to perform when going back in the navigation stack.
5+
/// </summary>
46
public enum GoBackType
57
{
8+
/// <summary>
9+
/// Performs the default go back operation, navigating to the previous page in the stack.
10+
/// </summary>
611
Default = 0,
12+
13+
/// <summary>
14+
/// Navigates back to the root page of the navigation stack.
15+
/// </summary>
716
ToRoot = 1
817
}

src/Maui/Prism.Maui/Navigation/Xaml/NavigateToExtension.cs

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,30 @@
1-

1+
using Microsoft.Extensions.Logging;
2+
23
namespace Prism.Navigation.Xaml;
34

5+
/// <summary>
6+
/// A markup extension that enables navigation to a specified page by name using Prism's navigation service.
7+
/// </summary>
48
[ContentProperty(nameof(Name))]
5-
public class NavigateToExtension : NavigationExtensionBase
9+
[RequireService([typeof(IProvideValueTarget)])]
10+
public partial class NavigateToExtension : NavigationExtensionBase
611
{
12+
/// <summary>
13+
/// Identifies the <see cref="Name"/> bindable property.
14+
/// </summary>
715
public static readonly BindableProperty NameProperty =
816
BindableProperty.Create(nameof(Name), typeof(string), typeof(NavigateToExtension), null);
917

18+
/// <summary>
19+
/// Gets or sets the name of the page to navigate to.
20+
/// </summary>
1021
public string Name
1122
{
1223
get => (string)GetValue(NameProperty);
1324
set => SetValue(NameProperty, value);
1425
}
1526

27+
/// <inheritdoc/>
1628
protected override async Task HandleNavigation(INavigationParameters parameters, INavigationService navigationService)
1729
{
1830
AddKnownNavigationParameters(parameters);
@@ -24,8 +36,12 @@ protected override async Task HandleNavigation(INavigationParameters parameters,
2436
}
2537
}
2638

39+
/// <inheritdoc/>
2740
protected override void Log(Exception ex, INavigationParameters parameters)
2841
{
29-
// TODO: Determine a good way to log
42+
if (Logger.IsEnabled(LogLevel.Error))
43+
{
44+
Logger.LogError(ex, "Navigation to {PageName} failed with parameters: {Parameters}", Name, parameters);
45+
}
3046
}
3147
}

src/Maui/Prism.Maui/Navigation/Xaml/NavigationExtensionBase.cs

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,32 +5,60 @@
55

66
namespace Prism.Navigation.Xaml;
77

8+
/// <summary>
9+
/// Provides a base class for navigation extensions in XAML, implementing <see cref="ICommand"/> for navigation actions.
10+
/// </summary>
811
public abstract class NavigationExtensionBase : TargetAwareExtensionBase<ICommand>, ICommand
912
{
13+
/// <summary>
14+
/// Identifies the <see cref="Animated"/> bindable property.
15+
/// </summary>
1016
public static readonly BindableProperty AnimatedProperty =
1117
BindableProperty.Create(nameof(Animated), typeof(bool), typeof(NavigationExtensionBase), true);
1218

19+
/// <summary>
20+
/// Identifies the <see cref="UseModalNavigation"/> bindable property.
21+
/// </summary>
1322
public static readonly BindableProperty UseModalNavigationProperty =
1423
BindableProperty.Create(nameof(UseModalNavigation), typeof(bool?), typeof(NavigationExtensionBase), null);
1524

25+
/// <summary>
26+
/// Gets a value indicating whether a navigation operation is currently in progress.
27+
/// </summary>
1628
protected internal bool IsNavigating { get; private set; }
1729

30+
/// <summary>
31+
/// Gets or sets a value indicating whether navigation should be animated.
32+
/// </summary>
1833
public bool Animated
1934
{
2035
get => (bool)GetValue(AnimatedProperty);
2136
set => SetValue(AnimatedProperty, value);
2237
}
2338

39+
/// <summary>
40+
/// Gets or sets a value indicating whether modal navigation should be used.
41+
/// </summary>
2442
public bool? UseModalNavigation
2543
{
2644
get => (bool?)GetValue(UseModalNavigationProperty);
2745
set => SetValue(UseModalNavigationProperty, value);
2846
}
2947

48+
/// <summary>
49+
/// Determines whether the command can execute in its current state.
50+
/// </summary>
51+
/// <param name="parameter">Data used by the command. If the command does not require data, this object can be set to null.</param>
52+
/// <returns>true if the command can execute; otherwise, false.</returns>
3053
public bool CanExecute(object parameter) => Page is not null && !IsNavigating;
3154

55+
/// <inheritdoc/>
3256
public event EventHandler CanExecuteChanged;
3357

58+
/// <summary>
59+
/// Executes the navigation command.
60+
/// </summary>
61+
/// <param name="parameter">The navigation parameters.</param>
3462
public async void Execute(object parameter)
3563
{
3664
var parameters = parameter.ToNavigationParameters(TargetElement);
@@ -51,19 +79,44 @@ public async void Execute(object parameter)
5179
}
5280
}
5381

82+
/// <summary>
83+
/// Provides the value of the extension, which is the command itself.
84+
/// </summary>
85+
/// <param name="serviceProvider">The service provider.</param>
86+
/// <returns>The command instance.</returns>
5487
protected override ICommand ProvideValue(IServiceProvider serviceProvider) =>
5588
this;
5689

90+
/// <summary>
91+
/// Logs navigation errors.
92+
/// </summary>
93+
/// <param name="ex">The exception that occurred.</param>
94+
/// <param name="parameters">The navigation parameters.</param>
5795
protected virtual void Log(Exception ex, INavigationParameters parameters)
5896
{
59-
// TODO: Determine a good way to log
60-
Logger.LogError(ex, "Error Navigating: \n[exception]");
97+
if (Logger.IsEnabled(LogLevel.Error))
98+
{
99+
Logger.LogError(ex, "Error Navigating: \n[exception]");
100+
}
61101
}
62102

103+
/// <summary>
104+
/// Handles the navigation logic. Must be implemented by derived classes.
105+
/// </summary>
106+
/// <param name="parameters">The navigation parameters.</param>
107+
/// <param name="navigationService">The navigation service.</param>
108+
/// <returns>A task representing the asynchronous operation.</returns>
63109
protected abstract Task HandleNavigation(INavigationParameters parameters, INavigationService navigationService);
64110

111+
/// <summary>
112+
/// Raises the <see cref="CanExecuteChanged"/> event.
113+
/// </summary>
65114
protected void RaiseCanExecuteChanged() => CanExecuteChanged?.Invoke(this, EventArgs.Empty);
66115

116+
/// <summary>
117+
/// Adds known navigation parameters such as <see cref="KnownNavigationParameters.Animated"/> and <see cref="KnownNavigationParameters.UseModalNavigation"/> to the provided <see cref="INavigationParameters"/>.
118+
/// </summary>
119+
/// <param name="parameters">The navigation parameters to which known values will be added.</param>
67120
protected void AddKnownNavigationParameters(INavigationParameters parameters)
68121
{
69122
parameters.Add(KnownNavigationParameters.Animated, Animated);
@@ -72,6 +125,10 @@ protected void AddKnownNavigationParameters(INavigationParameters parameters)
72125
parameters.Add(KnownNavigationParameters.UseModalNavigation, UseModalNavigation);
73126
}
74127

128+
/// <summary>
129+
/// Called when a property value changes.
130+
/// </summary>
131+
/// <param name="propertyName">The name of the property that changed.</param>
75132
protected override void OnPropertyChanged([CallerMemberName] string propertyName = null)
76133
{
77134
base.OnPropertyChanged(propertyName);
Lines changed: 62 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,88 @@
1-
namespace Prism.Navigation.Xaml;
1+
namespace Prism.Navigation.Xaml;
22

3+
/// <summary>
4+
/// Provides attached properties for tabbed page navigation and appearance in .NET MAUI applications.
5+
/// </summary>
36
public static class TabbedPage
47
{
8+
/// <summary>
9+
/// Identifies the <c>TitleBindingSource</c> attached property.
10+
/// Determines the source for the tab title binding.
11+
/// </summary>
512
public static BindableProperty TitleBindingSourceProperty =
6-
BindableProperty.CreateAttached("TitleBindingSource", typeof(TabBindingSource), typeof(TabbedPage), TabBindingSource.RootPage);
13+
BindableProperty.CreateAttached(
14+
"TitleBindingSource",
15+
typeof(TabBindingSource),
16+
typeof(TabbedPage),
17+
TabBindingSource.RootPage);
718

19+
/// <summary>
20+
/// Identifies the <c>Title</c> attached property.
21+
/// Sets the title for a tab in a <see cref="Microsoft.Maui.Controls.TabbedPage"/>.
22+
/// </summary>
823
public static BindableProperty TitleProperty =
9-
BindableProperty.CreateAttached("Title", typeof(string), typeof(TabbedPage), null);
24+
BindableProperty.CreateAttached(
25+
"Title",
26+
typeof(string),
27+
typeof(TabbedPage),
28+
null);
1029

30+
/// <summary>
31+
/// Identifies the <c>IconImageSource</c> attached property.
32+
/// Sets the icon image source for a tab in a <see cref="Microsoft.Maui.Controls.TabbedPage"/>.
33+
/// </summary>
1134
public static BindableProperty IconImageSourceProperty =
12-
BindableProperty.CreateAttached("IconImageSource", typeof(ImageSource), typeof(TabbedPage), null);
35+
BindableProperty.CreateAttached(
36+
"IconImageSource",
37+
typeof(ImageSource),
38+
typeof(TabbedPage),
39+
null);
1340

41+
/// <summary>
42+
/// Gets the value of the <c>TitleBindingSource</c> attached property from the specified <see cref="Page"/>.
43+
/// </summary>
44+
/// <param name="page">The page from which to get the property value.</param>
45+
/// <returns>The <see cref="TabBindingSource"/> value.</returns>
1446
public static TabBindingSource GetTitleBindingSource(Page page) =>
1547
(TabBindingSource)page.GetValue(TitleBindingSourceProperty);
1648

49+
/// <summary>
50+
/// Sets the value of the <c>TitleBindingSource</c> attached property on the specified <see cref="Page"/>.
51+
/// </summary>
52+
/// <param name="page">The page on which to set the property value.</param>
53+
/// <param name="bindingSource">The <see cref="TabBindingSource"/> value to set.</param>
1754
public static void SetTitleBindingSource(Page page, TabBindingSource bindingSource) =>
1855
page.SetValue(TitleBindingSourceProperty, bindingSource);
1956

57+
/// <summary>
58+
/// Gets the value of the <c>Title</c> attached property from the specified <see cref="Page"/>.
59+
/// </summary>
60+
/// <param name="page">The page from which to get the property value.</param>
61+
/// <returns>The title string.</returns>
2062
public static string GetTitle(Page page) =>
2163
(string)page.GetValue(TitleProperty);
2264

65+
/// <summary>
66+
/// Sets the value of the <c>Title</c> attached property on the specified <see cref="Page"/>.
67+
/// </summary>
68+
/// <param name="page">The page on which to set the property value.</param>
69+
/// <param name="title">The title string to set.</param>
2370
public static void SetTitle(Page page, string title) =>
2471
page.SetValue(TitleProperty, title);
2572

73+
/// <summary>
74+
/// Gets the value of the <c>IconImageSource</c> attached property from the specified <see cref="Page"/>.
75+
/// </summary>
76+
/// <param name="page">The page from which to get the property value.</param>
77+
/// <returns>The <see cref="ImageSource"/> for the tab icon.</returns>
2678
public static ImageSource GetIconImageSource(Page page) =>
2779
(ImageSource)page.GetValue(IconImageSourceProperty);
2880

81+
/// <summary>
82+
/// Sets the value of the <c>IconImageSource</c> attached property on the specified <see cref="Page"/>.
83+
/// </summary>
84+
/// <param name="page">The page on which to set the property value.</param>
85+
/// <param name="imageSource">The <see cref="ImageSource"/> to set as the tab icon.</param>
2986
public static void SetIconImageSource(Page page, ImageSource imageSource) =>
3087
page.SetValue(IconImageSourceProperty, imageSource);
31-
}
88+
}

0 commit comments

Comments
 (0)