My Goal is to NOT create dependencies between ViewModels.
I have .NET 7 MAUI project.
The situation is simple.

我有MainPage,并且我使用DI将ViewModel MainPageViewModel链接到它

services.AddSingleton<MainPageViewModel>();

services.AddSingleton<MainPage>(provider =>
{
    return new MainPage()
    {
        BindingContext = provider.GetRequiredService<MainPageViewModel>(),
    };
});

它工作正常,创建了ViewModel,并将其分配给MainPage个AS中的BindingContext个,太棒了.

现在,当我像这样将另一个 children 视图放入MainPage内时

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:MyNamespace"
             x:Class="MyNamespace.MainPage">
    
            <MyNamespace:ChildView />

</ContentPage>

我将它注册到它的ViewModel中,如下所示

services.AddSingleton<ChildViewModel>();

services.AddSingleton<ChildView>(provider =>
{
    return new ChildView()
    {
        BindingContext = provider.GetRequiredService<ChildViewModel>(),
    };
});

The MainPage create the ChildView directly (by calling its parameterless constructor) without consulting the DI Container
This is causing the lack of Binding for the ViewModel.

  1. 我不想在MainPageViewModel内创建ChildViewModel并传递它.
  2. 在Prism中,这个问题可以使用区域解决,但目前Prism不支持毛伊语
  3. MainPage的创造是这样的
<?xml version="1.0" encoding="UTF-8" ?>
<Shell
    x:Class="Trex.Mobile.App.AppShell"
    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:local="clr-namespace:MyNamespace"
    Shell.FlyoutBehavior="Disabled">

    <ShellContent
        Title="Home"
        ContentTemplate="{DataTemplate local:MainPage}"
        Route="MainPage" />

</Shell>

and by using this way, the DI container is used.
Can I use something like that for my ChildView or should I change something fundamentally

推荐答案

我认为使用DI容器创建ChildView是不可能的,因为Shell不会实例化它.

由于MainPage实例是由Shell创建的,因此您可以使用构造函数注入:

public partial class MainPage : ContentPage
{
    public MainPage(MainPageViewModel viewModel)
    {
        InitializeComponent();
        BindingContext = viewModel;
    }
}

然后,正如我在this answer中所描述的,您可以创建一个ServiceHelper类,如下所示:

public static class ServiceHelper
{
    public static IServiceProvider Services { get; private set; }

    public static void Initialize(IServiceProvider serviceProvider) => 
        Services = serviceProvider;

    public static T GetService<T>() => Services.GetService<T>();
}

ChildViewMainPage实例化,不能使用Shell的构造函数注入,但您可以使用上面的ServiceHelper来解析ChildViewModel:

public partial class ChildView : ContentView
{
    public ChildView()
    {
        InitializeComponent();
        BindingContext = ServiceHelper.GetService<ChildViewModel>();
    }
}

最后,注册所有依赖项并设置ServiceHelper:

builder.Services.AddSingleton<MainPage>();
builder.Services.AddSingleton<MainPageViewModel>();
builder.Services.AddSingleton<ChildView>();
builder.Services.AddSingleton<ChildViewModel>();

var app = builder.Build();

//we must initialize our service helper before using it
ServiceHelper.Initialize(app.Services);

return app;

Csharp相关问答推荐

默认的PSHost实现是什么(用于RunspacePool)?

如何在C#中使用并行主义将数据表转换为动态对象

如何定义所有项目的解决方案版本?

我应该将新的httpReportMessage()包装在using声明中吗?

使用其可能实现的基类和接口的属性的方法

如何禁用ASP.NET MVP按钮,以便无法使用开发人员控制台重新启用它

获取ASP.NET核心身份认证cookie名称

Unity中的刚体2D运动

Select Many和默认IfEmpty内部Select Many错误工作

如何在C#中使用正则表达式抓取用逗号分隔的两个单词?

在路由中使用枚举

为基本审计设置Audit.EntityFramework.Core

如何在VS代码中为C#DotNet配置.json选项以调试内部终端的控制台应用程序

HelperText属性不支持复杂内容(混合C#和标记)

Celler ArgumentExpression是否期望在所有情况下都捕获允许空值的运算符?

基于C#方法的EF核心过滤查询(缓冲与流)

如何从SignalR获取连接客户端的域

为什么我的属性即使没有显式地设置任何[必需]属性,也会显示验证?

SharpZipLib在文件名前加上目录名,生成tar.gz

无效的Zip文件-Zip存档