XAML MAUI中嵌套视图时的依赖注入

laik7k3q  于 2023-06-19  发布在  其他
关注(0)|答案(1)|浏览(162)

我试图嵌套视图,它使用MVVM,因此有一个ViewModel注入其中。OuterView后面的代码以及InnerView后面的xaml实际上并不相关,因此为了简洁起见,我将它们以及所有功能都保留下来。视图和视图模型被注册为服务,所以DI应该可以工作。
结构如下:

public partial class {
   public InnerView(InnerViewModel viewModel){
       BindingContext = viewModel;
       InitializeComponent();
   }
}
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:pages="clr-namespace:Example.Views"
             x:Class="Example.Views.OuterView"
             x:DataType="viewModels:OuterViewModel">
    <VerticalStackLayout name="InnerViewWrapper">
        <pages:InnerView/>
    </VerticalStackLayout>
</ContentPage>

这给了我一个错误“类型'InnerView'不可用作对象元素,因为它[...]没有定义无参数构造函数[...]”。这是有意义的,所以我开始在我的代码背后添加视图。

StockHistoryGraph? view = Handler?.MauiContext?.Services.GetServices<StockHistoryGraph>().FirstOrDefault(defaultValue: default);
if (view is not null) 
    InnerViewWrapper.Add(view);

这似乎是一个非常复杂的问题,所以我的问题是:
有没有一种方法可以在xaml文件中声明的视图上使用DI?

qoefvg9y

qoefvg9y1#

这里有三种方法来修复InnerView,使其与无参数构造函数一起工作。
前两个涉及在代码隐藏中设置BindingContext。
第三,避免需要BindingContext。
在所有解决方案中,InnerView不得有设置BindingContext的XAML。

修复#1:new InnerViewModel而不是DI:

public InnerView()
{
    InitializeComponent();
    BindingContext = new InnerViewModel();
}

修复#2:显式解析服务(即使InnerViewModel需要DI注入参数也有效):

public InnerView()
{
    InitializeComponent();
    BindingContext = Application.Current.Handler.MauiContext.Services.GetService<InnerViewModel>();
}

修复#3:代码InnerView,使其访问其属性,而无需设置BindingContext:

<SomeElement SomeAttribute="{Binding MyProperty, Source={RelativeSource Self}}" />
  <-- OPTIONAL -->
  <SomeElement SomeAttribute="{Binding VM.MyProperty2, Source={RelativeSource Self}}" />
public partial class InnerView : ContentView
{
    // OPTIONAL: If you really want a view model for this custom component
    // (usually not needed; just put properties in "this",
    //  as seen with "MyProperty".)
  private InnerViewModel VM { get; set; }

  public SomeType MyProperty { get; set; }

  public InnerView()
  {
    InitializeComponent();
    // NO "BindingContext = ...;"

    // OPTIONAL
    VM = new InnerViewModel();
    // OR (works even if InnerViewModel has DI-injected parameters)
    VM = Application.Current.Handler.MauiContext.Services.GetService<InnerViewModel>();
  }
}

// OPTIONAL
public class InnerViewModel
{
    public SomeType2 MyProperty2 { get; set; }
}

奖励:应用服务属性

缩短:

Application.Current.Handler.MauiContext.Services

致:

App.Services

例如:... = App.Services.GetService<SomeType>();
将service provider注入到App的(App.xaml.cs)构造函数中,并为其设置属性:

... class App
{
    public readonly IServiceProvider Services;

    public App(IServiceProvider services)
    {
        ...

        Services = services;
    }
}

相关问题