Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: enable nullability for mvvm helpers #3131

Merged
merged 2 commits into from
May 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -208,3 +208,9 @@ FakesAssemblies/

# Binlog
*.binlog

# macOS
.DS_Store

# VSCode
.mono
78 changes: 40 additions & 38 deletions src/Maui/Prism.Maui/Common/MvvmHelpers.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
#nullable enable
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using Prism.Dialogs;
using Prism.Navigation;
Expand All @@ -9,16 +11,16 @@

namespace Prism.Common;

public static class MvvmHelpers

Check warning on line 14 in src/Maui/Prism.Maui/Common/MvvmHelpers.cs

View workflow job for this annotation

GitHub Actions / build-prism-maui / Build Prism.Maui

Missing XML comment for publicly visible type or member 'MvvmHelpers'
{
public static void InvokeViewAndViewModelAction<T>(object view, Action<T> action) where T : class
public static void InvokeViewAndViewModelAction<T>(object? view, Action<T> action) where T : class

Check warning on line 16 in src/Maui/Prism.Maui/Common/MvvmHelpers.cs

View workflow job for this annotation

GitHub Actions / build-prism-maui / Build Prism.Maui

Missing XML comment for publicly visible type or member 'MvvmHelpers.InvokeViewAndViewModelAction<T>(object?, Action<T>)'
{
if (view is T viewAsT)
{
action(viewAsT);
}

if (view is BindableObject element && element.BindingContext is T viewModelAsT)
if (view is BindableObject { BindingContext: T viewModelAsT })
{
action(viewModelAsT);
}
Expand All @@ -32,14 +34,14 @@
}
}

public static async Task InvokeViewAndViewModelActionAsync<T>(object view, Func<T, Task> action) where T : class
public static async Task InvokeViewAndViewModelActionAsync<T>(object? view, Func<T, Task> action) where T : class

Check warning on line 37 in src/Maui/Prism.Maui/Common/MvvmHelpers.cs

View workflow job for this annotation

GitHub Actions / build-prism-maui / Build Prism.Maui

Missing XML comment for publicly visible type or member 'MvvmHelpers.InvokeViewAndViewModelActionAsync<T>(object?, Func<T, Task>)'
{
if (view is T viewAsT)
{
await action(viewAsT);
}

if (view is BindableObject element && element.BindingContext is T viewModelAsT)
if (view is BindableObject { BindingContext: T viewModelAsT })
{
await action(viewModelAsT);
}
Expand All @@ -49,15 +51,15 @@
var children = page.GetChildRegions();
if (children is not null)
foreach (var child in children)
await InvokeViewAndViewModelActionAsync<T>(child, action);
await InvokeViewAndViewModelActionAsync(child, action);
}
}

public static void DestroyPage(IView view)
public static void DestroyPage(IView? view)

Check warning on line 58 in src/Maui/Prism.Maui/Common/MvvmHelpers.cs

View workflow job for this annotation

GitHub Actions / build-prism-maui / Build Prism.Maui

Missing XML comment for publicly visible type or member 'MvvmHelpers.DestroyPage(IView?)'
{
try
{
DestroyChildren(view);

Check warning on line 62 in src/Maui/Prism.Maui/Common/MvvmHelpers.cs

View workflow job for this annotation

GitHub Actions / build-prism-maui / Build Prism.Maui

Possible null reference argument for parameter 'page' in 'void MvvmHelpers.DestroyChildren(IView page)'.

InvokeViewAndViewModelAction<IDestructible>(view, v => v.Destroy());

Expand Down Expand Up @@ -96,7 +98,7 @@
}
}

public static void DestroyWithModalStack(Page page, IList<Page> modalStack)
public static void DestroyWithModalStack(Page? page, IList<Page?> modalStack)
{
foreach (var childPage in modalStack.Reverse())
{
Expand All @@ -105,15 +107,15 @@
DestroyPage(page);
}

public static T GetImplementerFromViewOrViewModel<T>(object view)
public static T? GetImplementerFromViewOrViewModel<T>(object view)
where T : class
{
if (view is T viewAsT)
{
return viewAsT;
}

if (view is VisualElement element && element.BindingContext is T vmAsT)
if (view is VisualElement { BindingContext: T vmAsT })
{
return vmAsT;
}
Expand All @@ -136,12 +138,12 @@
return path == viewType.Name || path == viewType.FullName;
}

public static void OnNavigatedFrom(object view, NavigationContext navigationContext)
public static void OnNavigatedFrom(object? view, NavigationContext navigationContext)
{
InvokeViewAndViewModelAction<IRegionAware>(view, x => x.OnNavigatedFrom(navigationContext));
}

public static void OnNavigatedTo(object view, NavigationContext navigationContext)
public static void OnNavigatedTo(object? view, NavigationContext navigationContext)
{
InvokeViewAndViewModelAction<IRegionAware>(view, x => x.OnNavigatedTo(navigationContext));
}
Expand All @@ -161,35 +163,35 @@
return implementer?.CanNavigate(parameters) ?? true;
}

public static void OnNavigatedFrom(object page, INavigationParameters parameters)
public static void OnNavigatedFrom(object? page, INavigationParameters parameters)
{
if (page != null)
InvokeViewAndViewModelAction<INavigatedAware>(page, v => v.OnNavigatedFrom(parameters));
}

public static async Task OnInitializedAsync(object page, INavigationParameters parameters)
public static async Task OnInitializedAsync(object? page, INavigationParameters parameters)
{
if (page is null) return;

InvokeViewAndViewModelAction<IInitialize>(page, v => v.Initialize(parameters));
await InvokeViewAndViewModelActionAsync<IInitializeAsync>(page, async v => await v.InitializeAsync(parameters));
}

private static bool HasKey(this IEnumerable<KeyValuePair<string, object>> parameters, string name, out string key)
private static bool HasKey(this IEnumerable<KeyValuePair<string, object>> parameters, string name, [MaybeNullWhen(returnValue: false)] out string key)
{
key = parameters.Select(x => x.Key).FirstOrDefault(k => k.Equals(name, StringComparison.InvariantCultureIgnoreCase));
return !string.IsNullOrEmpty(key);
}

public static void OnNavigatedTo(object page, INavigationParameters parameters)
public static void OnNavigatedTo(object? page, INavigationParameters parameters)
{
if (page != null)
InvokeViewAndViewModelAction<INavigatedAware>(page, v => v.OnNavigatedTo(parameters));
}

public static Page GetOnNavigatedToTarget(Page page, IView mainPage, bool useModalNavigation)
public static Page? GetOnNavigatedToTarget(Page page, IView? mainPage, bool useModalNavigation)
{
Page target;
Page? target;
if (useModalNavigation)
{
var previousPage = GetPreviousPage(page, page.Navigation.ModalStack);
Expand All @@ -210,9 +212,9 @@
return target;
}

public static Page GetOnNavigatedToTargetFromChild(IView target)
public static Page? GetOnNavigatedToTargetFromChild(IView? target)
{
Page child = null;
Page? child = null;

if (target is FlyoutPage flyout)
child = flyout.Detail;
Expand All @@ -230,9 +232,9 @@
return null;
}

public static Page GetPreviousPage(Page currentPage, System.Collections.Generic.IReadOnlyList<Page> navStack)
public static Page? GetPreviousPage(Page currentPage, IReadOnlyList<Page?> navStack)
{
Page previousPage = null;
Page? previousPage = null;

int currentPageIndex = GetCurrentPageIndex(currentPage, navStack);
int previousPageIndex = currentPageIndex - 1;
Expand All @@ -242,7 +244,7 @@
return previousPage;
}

public static int GetCurrentPageIndex(Page currentPage, System.Collections.Generic.IReadOnlyList<Page> navStack)
public static int GetCurrentPageIndex(Page currentPage, IReadOnlyList<Page?> navStack)
{
int stackCount = navStack.Count;
for (int x = 0; x < stackCount; x++)
Expand All @@ -255,14 +257,14 @@
return stackCount - 1;
}

public static Page GetCurrentPage(Page mainPage) =>
public static Page? GetCurrentPage(Page mainPage) =>
_getCurrentPage(mainPage);

[EditorBrowsable(EditorBrowsableState.Never)]
public static void SetCurrentPageDelegate(Func<Page, Page> getCurrentPageDelegate) =>
public static void SetCurrentPageDelegate(Func<Page, Page?> getCurrentPageDelegate) =>
_getCurrentPage = getCurrentPageDelegate;

private static Func<Page, Page> _getCurrentPage = mainPage =>
private static Func<Page, Page?> _getCurrentPage = mainPage =>
{
var page = mainPage;

Expand All @@ -273,7 +275,7 @@
return EvaluateCurrentPage(page);
};

private static Page GetTarget(Page target)
private static Page? GetTarget(Page? target)
{
return target switch
{
Expand All @@ -281,18 +283,18 @@
TabbedPage tabbed => GetTarget(tabbed.CurrentPage),
NavigationPage navigation => GetTarget(navigation.CurrentPage),
ContentPage page => page,
_ => throw new NotSupportedException($"The page type '{target.GetType().FullName}' is not supported.")

Check warning on line 286 in src/Maui/Prism.Maui/Common/MvvmHelpers.cs

View workflow job for this annotation

GitHub Actions / build-prism-maui / Build Prism.Maui

Dereference of a possibly null reference.
};
}

private static Page EvaluateCurrentPage(Page target)
private static Page? EvaluateCurrentPage(Page? target)
{
Page child = GetTarget(target);
Page? child = GetTarget(target);

if (child is not null)
target = GetOnNavigatedToTargetFromChild(child);

if (target is Page page)
if (target is { } page)
{
if (target is IDialogContainer)
{
Expand All @@ -319,9 +321,9 @@
{
var navigationService = Navigation.Xaml.Navigation.GetNavigationService(navigationPage.CurrentPage);
var result = await navigationService.GoBackAsync();
if (result.Exception is NavigationException navEx && navEx.Message == NavigationException.CannotPopApplicationMainPage)
if (result.Exception is NavigationException { Message: NavigationException.CannotPopApplicationMainPage })
{
Application.Current.Quit();
Application.Current?.Quit();
}
}

Expand All @@ -335,13 +337,13 @@
},
};
var result = await navigationService.GoBackAsync(navParams);
if (result.Exception is NavigationException navEx && navEx.Message == NavigationException.CannotPopApplicationMainPage)
if (result.Exception is NavigationException { Message: NavigationException.CannotPopApplicationMainPage })
{
Application.Current.Quit();
Application.Current?.Quit();
}
}

public static void HandleSystemGoBack(IView previousPage, IView currentPage)
public static void HandleSystemGoBack(IView? previousPage, IView? currentPage)
{
var parameters = new NavigationParameters();
parameters.GetNavigationParametersInternal().Add(KnownInternalParameters.NavigationMode, NavigationMode.Back);
Expand All @@ -352,22 +354,22 @@

internal static bool HasDirectNavigationPageParent(Page page)
{
return page?.Parent != null && page?.Parent is NavigationPage;
return page.Parent is NavigationPage;
}

internal static bool HasNavigationPageParent(Page page) =>
HasNavigationPageParent(page, out var _);

internal static bool HasNavigationPageParent(Page page, out NavigationPage navigationPage)
internal static bool HasNavigationPageParent(Page page, out NavigationPage? navigationPage)
{
if (page?.Parent != null)
if (page.Parent != null)
{
if (page.Parent is NavigationPage navParent)
{
navigationPage = navParent;
return true;
}
else if ((page.Parent is TabbedPage) && page.Parent?.Parent is NavigationPage navigationParent)
else if (page.Parent is TabbedPage && page.Parent?.Parent is NavigationPage navigationParent)
{
navigationPage = navigationParent;
return true;
Expand Down
2 changes: 1 addition & 1 deletion src/Prism.Core/Navigation/NavigationResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public NavigationResult(bool success)
/// Initializes a new NavigationResult with an <see cref="Exception"/>
/// </summary>
/// <param name="ex">The <see cref="Exception"/> encountered as part of the navigation.</param>
public NavigationResult(Exception ex)
public NavigationResult(Exception? ex)
{
Exception = ex;
}
Expand Down
Loading