使用 Simple Injector 在运行时注入数据解析模型

Injecting data resolved models at runtime with Simple Injector

我正在使用 WPF 中的简单注入器构建一个应用程序,我遇到了 运行 问题,我想在 运行 时解决我的模型注入我的 ViewModels 的问题。例如,假设我有一个 window 来编辑需要带有用户模型的 ViewModel 的用户。这个用户模型是从列表中选择的,然后注入到 ViewModel 的构造函数中。我如何使用 Simple Injector 将这些数据输入到 ViewModel 中?这可能吗?我想如果有可能我会使用某种形式的工厂吗?我正在讨论是否将 Simple Injector 用于除我的 MVVM 组件之外的所有内容作为解决方法——除非我能找到一个好的解决方案。

如果我应该 post 一些示例代码或类似的东西来更清楚地定义问题,请告诉我。这是我第一个 运行 使用 DI 容器,我想了解如何使用它来最好地设计我的应用程序。

您不应该将模型注入到您的 ViewModel 中。

听起来您更需要一个活动 aggregator/messanger。您可以将事件聚合器注入您的视图模型并订阅某个事件并将其从另一个 ViewModel 中提升。

public class CustomersViewModel 
{
    private readonly IEventAggregator eventAggregator;

    public CustomersViewModel(IEventAggregator eventAggregator) 
    {
        if(eventAggregator==null) 
        {
            throw new ArgumentNullException("eventAggregator");
        }

        this.eventAggregator = eventAggregator;
    }

    private Customer selectedCustomer;
    public Customer SelectedCustomer
    {
        get { return selectedCustomer; }
        set 
        {
            if(selectedCustomer!=value) 
            {
                selectedCustomer = value;
                eventAggregator.Publish(new CustomerSelectedEvent(selectedCustomer);
            }
        }
    }
}

public class CustomerOrdersViewModel 
{
    private readonly IEventAggregator eventAggregator;
    private readonly IOrderRepository orderRepository;

    private ObservableCollection<Order> orders;
    public ObservableCollection<Order> Orders {
        get { return orders; } 
        set 
        {
            if(orders != value)
            {
                orders = value;
                OnPropertyChanged("Orders");
            }
        }
    }

    public CustomerDetailViewModel(IEventAggregator eventAggregator, IOrderRepository orderRepository) 
    {
        if(eventAggregator==null) 
        {
            throw new ArgumentNullException("eventAggregator");
        }

        this.eventAggregator = eventAggregator;
        this.eventAggregator.Subscribe<CustomerSelectedEvent>(OnCustomerSelected);
        ...
    }

    private async void OnCustomerSelected(CustomerSelectedEvent event) 
    {
        Orders = new ObservableCollection<Order>(await orderRepository.GetOrdersByCustomer(event.Customer.Id);
    }
}

其中 SelectedCustomerEvent 将是一个简单的 POCO class。

public class SelectedCustomerEvent 
{
    public Customer Customer { get; }

    public SelectedCustomerEvent(Customer customer) 
    {
        // C# 6.0, otherwise add a private setter
        Customer = customer;
    }
}

事件聚合器的实现有点超出范围,但是 messanger/event 聚合器(例如 Prism PubSubEvents)附带了一些框架。

使用您想要的首选方法确实是不可能的。那是因为你的设计不是最优的。如您所见,here 在您的应用程序组件中注入运行时数据是一种反模式。

用于编辑用户的模型是运行时数据,因此应该通过方法注入流经您的应用程序。

所以你可以像这样解决这个问题:

public interface IViewModel<T>
{
    void EditItem(T item);
}

class UserEditViewModel : IViewModel<User>
{
    public void EditItem(User item)
    {
        // bind properties etc...
    }
}

您通常会在您的用户主视图模型中注入 IViewModel<User>

基于 this and this 设计,您可以想象出一个更加灵活的解决方案。如果您将编辑用户视为执行您刚刚触发的命令并在完成时 returns,您可以定义一个基础组件,如 link 中的 QueryProcessor。这将成为一个 EditProcessor 来处理您在应用程序中的所有编辑操作。实现非常简单,看起来像:

class EditProcessor : IEditProcessor
{
    private readonly Container container;

    public EditProcessor(Container container)
    {
        this.container = container;
    }

    public void EditItem<T>(T item)
    {
        var viewModel = typeof (IViewModel<>).MakeGenericType(typeof (T));
        dynamic instance = container.GetInstance(viewModel);

        instance.EditItem((dynamic) item);
    }
}

现在在任何需要编辑模型的地方,只需注入 IEditProcessor 并调用

this.editProcessor.EditItem(yourItem);

这个 EditProcessor 的简单实现可以扩展为各种不错的功能,例如在编辑前备份项目,以便用户可以取消编辑表单等。

如果您使用一些 MVVM 工具包将您的视图绑定到您的视图模型,那么这也是让您的 DI 容器和 MVVM 工具包很好地相互交互的地方。