在.NET MAUI应用程序中向视图模型注入服务

17

我正在尝试理解如何在.NET MAUI应用程序中实现依赖注入。

我有一个处理我的REST调用的服务类和它的接口,看起来像这样:

public class MyRestApiService : IMyRestApiService
{
   public async Task<string> Get()
   {
      // Do someting
   }
}

然后我将此放入我的 DI 容器中,在 MauiProgram.cs 文件中:

builder.Service.AddTransient<IMyRestApiService, MyRestApiService>();

我也有一个视图模型,将在我的 MainPage.xaml 中使用。问题是,如果我对我的服务进行构造函数注入,XAML 似乎不喜欢它。

MainPageViewModel 如下所示:

public class MainPageViewModel : BaseViewModel
{
   IMyRestApiService _apiService;
   public MainPageViewModel(IMyRestApiService apiService)
   {
      _apiService = apiService;
   }
}
当我尝试将 MainPageViewModel 定义为 MainPage.xaml 的视图模型时,如下所示,我遇到了错误:
<ContentPage.BindingContext>
   <vm:MainPageViewModel />
</ContentPage.BindingContext>

错误信息如下:

类型 MainPageViewModel 不能用作对象元素,因为它不是公共的,也没有定义公共的无参数构造函数或类型转换器。

我该如何将我的服务注入到视图模型中?

2个回答

14

您需要从第一页开始解决所有问题,让所有内容都落在正确的位置上并使依赖注入正常工作。

请看这个例子:https://github.com/jfversluis/MauiDependencyInjectionSample

您需要注册您的服务、视图模型和视图。 在您的情况下,在您的 MauiProgram.cs 中添加:

// Change scopes as needed, this seems to make sense
builder.Service.AddTransient<MainPage>();
builder.Service.AddTransient<MainPageViewModel>();
builder.Service.AddSingleton<IMyRestApiService, MyRestApiService>();

然后,在你的 App.xaml.cs 中开始注入你的(主要)页面:

public partial class App : Application
{
    public App(MainPage page)
    {
        InitializeComponent();

        MainPage = page;
    }
}

现在在你的MainPage.xaml.cs中添加一个像这样的构造函数:

public LoginPage(MainPageViewModel viewModel)
{
    InitializeComponent();

    BindingContext = viewModel;
}

从那里开始,一切都应该顺理成章地连接在一起。你所尝试的是

<ContentPage.BindingContext>
   <vm:MainPageViewModel />
</ContentPage.BindingContext>

基本上是通过属性设置 BindingContext。您可以这样做,但那么您将不得不自己指定参数并从依赖注入容器中解析它们,通常您不希望这样做。


1
我也在这样做。这种方法的一个缺点是你会失去XAML智能感知。为了恢复它,我在XAML中将设计时的d:ContentPage.BindingContext属性设置为vm:MainPageViewModel。虽然它会抱怨无法创建视图模型(因为它没有无参构造函数),但它可以让智能感知再次工作。 - Michal Diviš
我已经创建了一个包含该增强功能的PR - Michal Diviš
2
@MichalDiviš 谢谢你!不过我是指在 .NET MAUI 存储库中 :D 而且 Sam,你可能不想为你的页面和视图模型使用单例,因为它们现在会保留状态。例如,如果您打开某个产品的页面并编辑了一些内容,那么这些编辑可能会出现在您下次打开的不同产品中。 - Gerald Versluis
嘿@GeraldVersluis,抱歉。你是指maui-samples存储库还是其他存储库? - Michal Diviš
3
要在 XAML 部分中恢复 Intellisense,您还可以添加:
xmlns:vm="clr-namespace:SomeViewModels"
x:DataType ="vm:SomeViewModel"
- Stefan Ott
显示剩余2条评论

3

要将您的视图模型注入到视图中,实际上需要在其构造函数中进行,在代码后台中,像这样:

public partial class LoginPage : ContentPage {
    public LoginPage(ILoginViewModel loginViewModel) {
        BindingContext = loginViewModel;
        InitializeComponent();
    }
}

同时,您还需要注册使用依赖注入的视图:

builder.Service.AddTransient<LoginPage>();

据我所知,在XAML中,你不能像你现在这样使用DI来实例化一个视图模型。

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