Skip to content

Commit

Permalink
Added ViewModel paramater resolution, bump remaining projects to .NET 8
Browse files Browse the repository at this point in the history
  • Loading branch information
matt-goldman committed Oct 6, 2023
1 parent 85a7212 commit c2315fd
Show file tree
Hide file tree
Showing 5 changed files with 117 additions and 77 deletions.
3 changes: 1 addition & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -348,5 +348,4 @@ MigrationBackup/

# Ionide (cross platform F# VS Code tools) working folder
.ionide/
.meteor/generated
/src/DemoProject/.meteor/generated
.meteor/
6 changes: 3 additions & 3 deletions src/DemoProject/DemoProject.csproj
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net7.0-android;net7.0-ios;net7.0-maccatalyst</TargetFrameworks>
<TargetFrameworks Condition="$([MSBuild]::IsOSPlatform('windows'))">$(TargetFrameworks);net7.0-windows10.0.19041.0</TargetFrameworks>
<TargetFrameworks>net8.0-android;net8.0-ios;net8.0-maccatalyst</TargetFrameworks>
<TargetFrameworks Condition="$([MSBuild]::IsOSPlatform('windows'))">$(TargetFrameworks);net8.0-windows10.0.19041.0</TargetFrameworks>
<!-- Uncomment to also build the tizen app. You will need to install tizen by following this: https://github.com/Samsung/Tizen.NET -->
<!-- <TargetFrameworks>$(TargetFrameworks);net7.0-tizen</TargetFrameworks> -->
<!-- <TargetFrameworks>$(TargetFrameworks);net8.0-tizen</TargetFrameworks> -->
<OutputType>Exe</OutputType>
<RootNamespace>DemoProject</RootNamespace>
<UseMaui>true</UseMaui>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<UseMaui>true</UseMaui>
<Authors>Matt Goldman</Authors>
<Company></Company>
Expand Down
132 changes: 87 additions & 45 deletions src/Maui.Plugins.PageResolver/NavigationExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,63 +1,105 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Maui.Controls;
using System;
using System.Threading.Tasks;

namespace Maui.Plugins.PageResolver
namespace Maui.Plugins.PageResolver;

public static class NavigationExtensions
{
public static class NavigationExtensions
#region paramaterless navigation

/// <summary>
/// Resolves a page of type T (must inherit from Page) and pushes a new instance onto the navigation stack
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="navigation"></param>
/// <returns></returns>
public static async Task PushAsync<T>(this INavigation navigation) where T : Page
{
/// <summary>
/// Resolves a page of type T (must inherit from Page) and pushes a new instance onto the navigation stack
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="navigation"></param>
/// <returns></returns>
public static async Task PushAsync<T>(this INavigation navigation) where T : Page
{
var resolvedPage = Resolver.Resolve<T>();
var resolvedPage = Resolver.Resolve<T>();

await navigation.PushAsync(resolvedPage);
}
await navigation.PushAsync(resolvedPage);
}

/// <summary>
/// Resolves a page of type T (must inherit from Page) and pushes a new instance onto the navigation stack
/// </summary>
/// <typeparam name="T">The type of the page to be resolved</typeparam>
/// <param name="navigation"></param>
/// <param name="parameters">The constructor parameters expected by the page to be resolved</param>
/// <returns></returns>
public static async Task PushAsync<T>(this INavigation navigation, params object[] parameters) where T : Page
{
var resolvedPage = ActivatorUtilities.CreateInstance<T>(Resolver.GetServiceProvider(), parameters);
/// <summary>
/// Resolves a page of type T (must inherit from Page) and pushes a new modal instance onto the navigation stack
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="navigation"></param>
/// <returns></returns>
public static async Task PushModalAsync<T>(this INavigation navigation) where T : Page
{
var resolvedPage = Resolver.Resolve<T>();

await navigation.PushAsync(resolvedPage);
}
await navigation.PushModalAsync(resolvedPage);
}

#endregion

/// <summary>
/// Resolves a page of type T (must inherit from Page) and pushes a new modal instance onto the navigation stack
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="navigation"></param>
/// <returns></returns>
public static async Task PushModalAsync<T>(this INavigation navigation) where T : Page
{
var resolvedPage = Resolver.Resolve<T>();

await navigation.PushModalAsync(resolvedPage);
#region parameterized navigation

/// <summary>
/// Resolves a page of type T (must inherit from Page) and pushes a new instance onto the navigation stack
/// </summary>
/// <typeparam name="T">The type of the page to be resolved</typeparam>
/// <param name="navigation"></param>
/// <param name="parameters">The constructor parameters expected by the page to be resolved</param>
/// <returns></returns>
public static async Task PushAsync<T>(this INavigation navigation, params object[] parameters) where T : Page
{
var page = ResolvePage<T>(parameters);
await navigation.PushAsync(page);
}

/// <summary>
/// Resolves a page of type T (must inherit from Page) and pushes a new modal instance onto the navigation stack
/// </summary>
/// <typeparam name="T">The type of the page to be resolved</typeparam>
/// <param name="navigation"></param>
/// <param name="parameters">The constructor parameters expected by the page to be resolved</param>
/// <returns></returns>
public static async Task PushModalAsync<T>(this INavigation navigation, params object[] parameters) where T : Page
{
var page = ResolvePage<T>(parameters);
await navigation.PushModalAsync(page);
}


private static Page ResolvePage<T>(params object[] parameters) where T : Page
{
var serviceProvider = Resolver.GetServiceProvider();

// Try to get the ViewModel type.
var viewModelType = Type.GetType($"{typeof(T).FullName}ViewModel");
if (viewModelType == null)
{
return CreatePageWithoutViewModel<T>(serviceProvider, parameters);
}

/// <summary>
/// Resolves a page of type T (must inherit from Page) and pushes a new modal instance onto the navigation stack
/// </summary>
/// <typeparam name="T">The type of the page to be resolved</typeparam>
/// <param name="navigation"></param>
/// <param name="parameters">The constructor parameters expected by the page to be resolved</param>
/// <returns></returns>
public static async Task PushModalAsync<T>(this INavigation navigation, params object[] parameters) where T : Page
return CreatePageWithViewModel<T>(serviceProvider, viewModelType, parameters);
}

private static Page CreatePageWithoutViewModel<T>(IServiceProvider serviceProvider, params object[] parameters) where T : Page
{
return ActivatorUtilities.CreateInstance<T>(serviceProvider, typeof(T), parameters);
}

private static Page CreatePageWithViewModel<T>(IServiceProvider serviceProvider, Type viewModelType, params object[] parameters) where T : Page
{
var viewModel = ActivatorUtilities.CreateInstance(serviceProvider, viewModelType, parameters);

using (var scope = serviceProvider.CreateScope())
{
var resolvedPage = ActivatorUtilities.CreateInstance<T>(Resolver.GetServiceProvider(), parameters);
var scopedServiceProvider = scope.ServiceProvider;
var serviceCollection = new ServiceCollection();
serviceCollection.AddSingleton(viewModelType, viewModel);
var scopedProvider = serviceCollection.BuildServiceProvider();

await navigation.PushModalAsync(resolvedPage);
return ActivatorUtilities.CreateInstance<T>(scopedProvider, typeof(T));
}
}

#endregion
}
51 changes: 25 additions & 26 deletions src/Maui.Plugins.PageResolver/Resolver.cs
Original file line number Diff line number Diff line change
@@ -1,36 +1,35 @@
using Microsoft.Extensions.DependencyInjection;
using System;

namespace Maui.Plugins.PageResolver
namespace Maui.Plugins.PageResolver;

public static class Resolver
{
public static class Resolver
{
private static IServiceScope scope;
private static IServiceScope scope;

/// <summary>
/// Registers the service provider and creates a dependency scope
/// </summary>
/// <param name="sp"></param>
internal static void RegisterServiceProvider(IServiceProvider sp)
{
scope ??= sp.CreateScope();
}
/// <summary>
/// Registers the service provider and creates a dependency scope
/// </summary>
/// <param name="sp"></param>
internal static void RegisterServiceProvider(IServiceProvider sp)
{
scope ??= sp.CreateScope();
}

/// <summary>
/// Returns a resolved instance of the requested type.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
internal static T Resolve<T>() where T : class
{
var result = scope.ServiceProvider.GetRequiredService<T>();
/// <summary>
/// Returns a resolved instance of the requested type.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
internal static T Resolve<T>() where T : class
{
var result = scope.ServiceProvider.GetRequiredService<T>();

return result;
}
return result;
}

internal static IServiceProvider GetServiceProvider()
{
return scope.ServiceProvider;
}
internal static IServiceProvider GetServiceProvider()
{
return scope.ServiceProvider;
}
}

0 comments on commit c2315fd

Please sign in to comment.