Phil
Phil

Reputation: 522

.Net MAUI - AppShell navigation & dependency injection

I'm playing around with .Net Maui, AppShell and dependency injection.

I try to call a page with a constructor which takes the ViewModel of this page as parameter.

The constructor looks like this:

public AuthenticationPage(AuthenticationViewModel viewModel)
{
    InitializeComponent();
    BindingContext = viewModel;
}

In my MauiProgram.cs I registered both, the page and the VM

builder.Services.AddSingleton<AuthenticationViewModel>();
builder.Services.AddSingleton<AuthenticationPage>();

My App.xaml.cs looks like this:

public partial class App : Application
{
    public App()
    {
        InitializeComponent();
        MainPage = new AppShell();
    }
}

And my AppShell.xaml looks like this:

<Shell  xmlns="http://schemas.microsoft.com/dotnet/2021/maui" 
           xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
           xmlns:pages="clr-namespace:DeepBlue.Pages"
           xmlns:auth="clr-namespace:DeepBlue.Pages.Authentication"
           x:Class="DeepBlue.AppShell">

    <!-- Login and Registration Page -->
    <ShellContent Route="login"
                  ContentTemplate="{DataTemplate auth:AuthenticationPage}">
    </ShellContent>

    <!-- Main Page -->
    <FlyoutItem Route="main"
                FlyoutDisplayOptions="AsMultipleItems">
        <ShellContent Route="dashboard"
                      ContentTemplate="{DataTemplate pages:DashboardPage}"
                      Title="Home" />
    </FlyoutItem>

</Shell>

Now when I execute my Project, I get the following error:

System.MissingMethodException: 'No parameterless constructor defined for type 'DeepBlue.Pages.Authentication.AuthenticationPage'.'

Could someone please tell me why the dependency injection does not work in this case?

If I don't implement the AppShell, everthing is working fine.... I can call AuthenticationPage as MainPage via injection from my App.xaml.cs like this:

public App(AuthenticationPage page)
{
    InitializeComponent();
    MainPage = page
}

Thanks, Phil

Upvotes: 11

Views: 12820

Answers (3)

Aymane EL Jahrani
Aymane EL Jahrani

Reputation: 192

This is still happening and it doesn't really seem to be an issue.

Using DI with a HostBuilder as I used to do every single time for my applications doesn't work with Maui. Maui has its own app builder so you should not only add services as mentioned, but also make sure that you are using the right builder.

Here's a code that won't work with Maui :

var host = Host.CreateDefaultBuilder()
        .ConfigureAppConfiguration((context, builder) =>
        {
            // Add other configuration files...
            //builder.AddJsonFile("appsettings.local.json", optional: true);
        })
        .ConfigureServices((context, services) =>
        {
            ConfigureServices(context.Configuration, services);
        })
        .ConfigureLogging((_, logging) =>
        {
            logging.AddConsole();
        })
        .Build();

static void ConfigureServices(IConfiguration configuration,
        IServiceCollection services)
{
    
    // ...
    services.AddSingleton<MessageFactory>();
    services.AddSingleton<ResponseBuilder>();
    services.AddSingleton<ProtocolEventBus>();
    services.AddSingleton<NetworkSniffer>();
    services.AddSingleton<AppDelegate>();
    services.AddTransient<MainPage>();
    services.AddTransient<AppShell>();
}

}

But using Maui's builder :

var builder = MauiApp.CreateBuilder();
    builder.Services.AddSingleton<ProtocolEventBus>();
    builder.Services.AddSingleton<MessageFactory>();
    builder.Services.AddSingleton<ResponseBuilder>();
    builder.Services.AddSingleton<NetworkSniffer>();
    builder.Services.AddSingleton<AppDelegate>();
    builder.Services.AddTransient<MainPage>();
    builder.Services.AddTransient<AppShell>();
    builder
        .UseMauiApp<App>()
        .ConfigureFonts(fonts =>
        {
            fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
            fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
        });

Hope it helps !

That being said, I'm really not happy with the way Microsoft is going about .Net in OS X : So much potential, but so many bugs, misleading informations and still not that much ressources :/

Upvotes: 0

Marcel Wolterbeek
Marcel Wolterbeek

Reputation: 3702

The Maui DevBlogs of January 2022 suggested that this was implemented, but it seems like it is partly removed temporary because of some issues. For now there is a workaround: Add the view which needs DI in the services in MauiProgram.cs:

// Workaround for Shell/DataTemplates:
builder.Services.AddTransient<MainPage>();
builder.Services.AddTransient<AuthenticationPage>();

Hopefully DI support for Shell and DataTemplates will be implemented soon correctly.

Upvotes: 12

Gerald Versluis
Gerald Versluis

Reputation: 34013

Shell (and DataTemplates that is associated) does not have support for dependency injection (yet). Issues on the repository are opened here and here. And at the time of writing this answer a PR is open that adds this functionality. You can track the progress of that here.

Upvotes: 8

Related Questions