【问题标题】:How to pass an object to a ViewModel using dependency injection?如何使用依赖注入将对象传递给 ViewModel?
【发布时间】:2015-12-25 02:59:55
【问题描述】:

我需要将一个对象从一个视图模型传递到另一个视图模型。在我当前的实现中,我创建了一个 ProductVM 的静态实例,遵循这个 example,然后从实例访问它的属性。但从长远来看,传递静态实例似乎不是一个可靠的设计。

private static ProductVM _instance = new ProductVM();
public static ProductVMInstance { get { return _instance; } }

在研究提供静态视图模型实例的替代方案时,我发现constructor injection 是一个选项。

问题:

有没有人有任何例子,关于如何实现 ctor 注入来传递对象? (最好不要使用第三方框架)

ProductsVM:(保存要发送的属性的视图模型)

    public ProductModel SelectedProduct { get; set; }

CustomerOrdersVM:(SelectedProduct 需要传入的视图模型)

public class CustomerOrdersViewModel : IPageViewModel
{

    public CustomerOrdersViewModel()
    {                  

    }
}

【问题讨论】:

  • 您使用的是哪个 IoC 容器?这对于答案至关重要,因为每个 IoC (DI) 容器都有自己的 API
  • @Tseng 我正在使用 ApplicationVM 来注册每个 VM。特别不使用任何 IoC 容器。 hastebin.com/osopigozoc.avrasm

标签: c# object mvvm constructor-injection


【解决方案1】:

Rowbear 涵盖了 EventAggregators 的案例。它们不能在所有情况下都使用。

EventAggregator 模式只有在目标 ViewModel(及其对应的视图)已经实例化时才有用,因为只有这样 ViewModel 才会注册到事件以做出反应。

这不适用于 ViewModel/View 在显示之前必须实例化/导航的情况。一个示例是智能手机应用程序,您可以在其中单击产品并接收其详细信息或类似内容。

在这种情况下,您需要一个导航服务,您可以在其中将某个参数(productIdorderId 等)传递给导航调用,例如 navigationService.Navigate("OrderDetails", orderId);,并让您的 ViewModel 实现某种 INavigationAware接口,由导航服务调用,以防 ViewModel 实现此接口。

public class OrderDetailsViewModel : ViewModelBase, INavigationAware
{
    public async void OnNavigatedFrom(object parameter) 
    {
        var orderId = (int)parameter;
        var order = await orderRepository.GetOrderByIdAsync(orderId);

        // display your order in the ViewModel here
    }
}

导航服务附带了许多框架,企业应用程序中最受欢迎的是 Prism MVVM 框架(最初由 Microsoft 开发)

【讨论】:

  • 在这种情况下,将在打开 ProductView 之前注册 CustomerOrdersVM。所以我认为 EventAggregator 可能是要走的路。我没有这样的导航服务,我正在使用 VM 列表进行导航,如您之前评论的链接中发布的那样。
【解决方案2】:

您提供的example link 中接受的答案实际上描述了构造函数注入。答案 1 和 2 在技术上都描述了“构造函数注入”。为了在没有第三方框架的情况下实现构造函数注入,您基本上需要将 SelectedProduct 或 ProductsVM 实例传递给 CustomerOrdersVM 的构造函数。唯一剩下的是一个作为“注入器”的总体类或视图模型,它控制 CustomerOrdersVM 实例和 ProductsVM 实例的构造(或者至少有一个可以传递给 CustomerOrdersVM ctor 的实例的引用):

public class MainViewModel : ViewModelBase
{
    public MainViewModel()
    {
        ProductsViewModel = new ProductsVM();
        OrdersViewModel = new CustomerOrdersVM(ProductsViewModel);
    }
    public CustomerOrdersVM OrdersViewModel { get; private set; }

    public ProductsVM ProductsViewModel { get; private set; }
}

我参与了一个 MVVM(大部分)项目,该项目始终使用构造函数注入,而没有第三方注入器。这是有道理的,因为我们有一个包含多个视图模型作为其属性的总体对象(从技术上讲,它充当主要的父视图模型和注入器)。然而,它最终变得有些笨拙,因为一些视图模型在其构造函数中需要一个看似随机的其他视图模型。根据您的视图模型与模型或数据库/外部服务的清晰分离程度,对视图模型进行单元测试也可能变得更加困难,因为您可能会开始在视图模型中添加需要使用生产数据完全构建依赖项的逻辑。

这让我问你……为什么需要 CustomerOrderVM 中的 SelectedProduct?是因为用户交互会在 ProductsVM 中设置 SelectedProduct 属性,而您的 CustomerOrdersVM 需要知道它吗?如果是这样,您是否考虑过实施EventAggregator Pattern?当我团队中的某个人实现了这一点时,它使视图模型之间的信息传递变得轻而易举。视图模型将引用事件标记器,并在构造时订阅事件。这样,当您的用户选择产品时,您的 ProductsVM 可以采取行动,并发布您的 CustomerOrdersVM 可以订阅和采取行动的事件。

【讨论】:

  • 事件聚合器并不适用于所有情况,尤其不适用于导航。但是 OP 没有充分指定用例
  • @Tseng 用户将从 ProductsVM 中选择一个产品并设置一个数量。然后需要将此 SelectedProduct 传递给 CustomerOrdersVM,以便可以将其添加到 SelectedOrder。顺便说一句,我使用 AppVM 来注册每个 vm,所以我只是在 ProductVM 中传递 CustomerOrdersVM 并通过对象访问 SelectedProduct。我正在考虑重构 EventAggregator 模式,尽管它看起来很有用。
猜你喜欢
  • 1970-01-01
  • 2023-03-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-08
  • 2019-12-28
  • 2011-08-30
  • 1970-01-01
相关资源
最近更新 更多