【问题标题】:Dependency Injection WPF MVVM Navigation .NET Core依赖注入 WPF MVVM 导航 .NET Core
【发布时间】:2020-06-25 04:27:30
【问题描述】:

我需要一些帮助来了解如何在不将所有视图模型作为 MainViewModel 类构造函数中的参数的情况下实例化视图模型。

你们中的任何人都可以帮我弄清楚并摆脱构造函数中的这么多参数吗?我已经阅读过有关 FactoryPatterns 的信息,但我不明白如何实现它,或者这可能不是解决方案?无论如何,这是代码。

谢谢。请帮帮我,这让我发疯了!

app.xaml.cs

    private readonly ServiceProvider _serviceProvider;
    public App()
    {
        ServiceCollection services = new ServiceCollection();
        ConfigureServices(services);
        _serviceProvider = services.BuildServiceProvider();
    }

    private void ConfigureServices(ServiceCollection services)
    {
        services.AddSingleton<MainWindow>();
        // Services
        services.AddSingleton<ICustomerService, CustomerService>();
        // ViewModels
        services.AddScoped<MainViewModel>();
        services.AddScoped<CustomerViewModel>();
        services.AddScoped<CustomerAddViewModel>();
        services.AddScoped<CustomerEditViewModel>();
        services.AddScoped<ServiceViewModel>();
    }

    private void OnStartup(object sender, StartupEventArgs e)
    {
        var mainWindow = _serviceProvider.GetService<MainWindow>();
        mainWindow.DataContext = _serviceProvider.GetService<MainViewModel>();
        mainWindow.Show();
    }

MainViewMode.cs

public class MainViewModel : ViewModelBase
{
    private CustomerViewModel _customerViewModel;
    private CustomerAddViewModel _customerAddViewModel;
    private CustomerEditViewModel _customerEditViewModel;

    private ViewModelBase _selectedViewModel;
    public ViewModelBase SelectedViewModel
    {
        get => _selectedViewModel;
        set
        {
            _selectedViewModel = value;
            NotifyPropertyChanged();
        }
    }

    public RelayCommand CustCommand { get; set; }
    public RelayCommand ServCommand { get; set; }

    **public MainViewModel(
        CustomerViewModel customerViewModel,
        CustomerAddViewModel customerAddViewModel,
        CustomerEditViewModel customerEditViewModel)
    {
        _customerViewModel = customerViewModel;
        _customerAddViewModel = customerAddViewModel;
        _customerEditViewModel = customerEditViewModel;
        CustCommand = new RelayCommand(OpenCustomer);
    }**

    private void OpenCustomer()
    {
        SelectedViewModel = _customerViewModel;
    }

}

客户视图模型

    public class CustomerViewModel : ViewModelBase
    {
    private ICustomerService _repo;
    private ObservableCollection<Customer> _customers;
    public ObservableCollection<Customer> Customers
    {
        get => _customers;
        set
        {
            _customers = value;
            NotifyPropertyChanged();
        }
    }

    public CustomerViewModel(ICustomerService repo)
    {
        _repo = repo;
    }

    public async void LoadCustomers()
    {
        List<Customer> customers = await _repo.GetCustomers();
        Customers = new ObservableCollection<Customer>(customers);
    }

    
}

【问题讨论】:

  • 请注意,只有三个依赖项的类无需担心。尤其是在使用组合时,这很常见。根据您的设计和复杂性,您可以轻松获得 10 多个依赖项。这就是您主要使用 DI 框架的目的;以集中的方式自动创建具有复杂结构的实例。
  • 使用抽象工厂模式不一定会减少构造函数的参数数量,因为您仍然需要将工厂注入依赖类。并且使用例如单个工厂(或更糟糕的服务容器)在类内部创建依赖关系被认为是不好的做法,甚至是反模式,因为它隐藏了依赖关系或引入了紧密耦合。您通常使用工厂来抽象出动态类实例化。
  • 您可以从代码中的 di 容器显式解析。我更喜欢属性注入。如果实例化有一些复杂性,您可以使用惰性单例实例化作为包装工厂方法的一种方式。如果你使用 di,工厂方法应该在你的候选列表中。
  • 感谢您澄清了对 DI 的一些疑问。我会尝试 Andy 的建议,但这对我来说可能很复杂,因为我正在学习设计模式,而你所说的一切似乎超出了我目前的知识范围

标签: c# wpf mvvm .net-core dependency-injection


【解决方案1】:

您正在使用构造函数注入,这只是执行 DI 的方法之一。另一种方法是属性注入,您通常会这样做:

public class ClassToBeInjected
{
    [Inject]
    public SomeDataType PropertyToBeInjected {get; set;}

   ... etc ...
}

只要 ClassToBeInjected 是通过 DI 框架创建的,任何带有 [Inject] 标记的属性也将被自动注入。此外,使用 [Inject] 属性标记的 SomeDataType 的任何属性也将被注入,依此类推。

实现这一点的确切机制取决于您的 DI 框架。我在这里使用了[Inject] 属性,这是 Ninject 使用的,但每个框架都有自己的方法。

【讨论】:

  • 感谢先生的建议,从各方面来看,这都是个好主意
  • 请注意,OP 正在使用 .NET Core 的默认 DI 容器 (MS.DI),并且该容器不支持属性注入,这意味着像 [Inject] 属性之类的东西不能(很容易)被添加到它。另请注意,属性注入带有myriad of downsides,不应忽略。
  • @Laycoonz Steven 比我更有资格谈论这个话题,看来我们都有一些阅读要做。
【解决方案2】:

您不需要将所有依赖项传递给 MainViewModel,现在这很容易,因为您只有三个,如果它们是 20 个呢?我认为最好的办法是注入依赖容器并从那里获取所有视图模型。

public class MainViewModel : ViewModelBase{

    private ServiceProvider _serviceProvider;

    public MainViewModel(IServiceProvider provider)
    {
        _serviceProvider = provider;
    }

    private void SomeMethod(){
        CustomerViewModel viewModel = _serviceProvider.GetRequiredService(CustomerViewModel);
    }
}

【讨论】:

    猜你喜欢
    • 2023-03-27
    • 1970-01-01
    • 2016-05-22
    • 1970-01-01
    • 2021-10-23
    • 1970-01-01
    • 2021-02-02
    • 1970-01-01
    • 2020-12-20
    相关资源
    最近更新 更多