.Net MAUI - AppShell导航和依赖注入

8
我正在尝试使用 .Net Maui、AppShell 和依赖注入技术。
我试图调用一个带有 ViewModel 参数的构造函数来打开一个页面。
该构造函数如下:
public AuthenticationPage(AuthenticationViewModel viewModel)
{
    InitializeComponent();
    BindingContext = viewModel;
}

在我的MauiProgram.cs文件中,我同时注册了页面和VM。
builder.Services.AddSingleton<AuthenticationViewModel>();
builder.Services.AddSingleton<AuthenticationPage>();

我的 App.xaml.cs 文件如下:

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

我的 AppShell.xaml 看起来像这样:

<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>

现在当我执行我的项目时,我得到了以下错误:

System.MissingMethodException: '未为类型“DeepBlue.Pages.Authentication.AuthenticationPage”定义无参构造函数。'

请问为什么依赖注入在这种情况下不起作用?

如果我不实现AppShell,一切都能正常运行...... 我可以通过从我的App.xaml.cs注入来调用AuthenticationPage作为MainPage,如下所示:

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

谢谢,Phil

3个回答

11

2022年1月的Maui DevBlogs暗示已经实现了这一点,但由于存在一些问题,似乎部分被暂时删除。目前有一个解决方法:在MauiProgram.cs中将需要依赖注入的视图添加到服务中。

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

希望在不久的将来,Shell和DataTemplates的DI支持能够正确地实现。

1
截至2023年5月,这个问题似乎仍然存在。然而,解决方法似乎非常有效。 - John Christopher Linstrum

6

目前Shell(以及相关的DataTemplates)还没有支持依赖注入。问题已经在该项目的这里这里开放讨论。在回答写作时,有一个贡献者正在开发添加此功能的Pull Request。您可以在这里跟踪其进展。


0
这仍然在发生,而且似乎并不是一个问题。
在Maui中,使用HostBuilder和DI(依赖注入)的方式,就像我以前为我的应用程序做的那样,是行不通的。Maui有自己的应用程序构建器,所以你不仅需要添加服务,还要确保你使用了正确的构建器。
以下是一个在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>();
}

}

但是使用Maui的构建器:
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");
        });

希望能有所帮助!
话虽如此,我对微软在OS X上推行.Net的方式并不满意:潜力巨大,但是存在太多的错误、误导性信息,而且资源还不是很充足:/

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接