具有依赖注入的MVVM ViewModels中的陈旧数据

时间:2012-02-14 19:09:00

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

在我的WPF应用程序中,我使用MVVM模式和依赖注入。

从数据库中准备数据的ViewModel将注入到构造函数中的存储库。它们还使用构造函数中的存储库中的数据填充属性。

ViewModel都是在ViewModelLocator类的静态构造函数中创建的,所有View都使用它来绑定到它们的ViewModel。

这有以下缺点:

  1. 视图中的数据永远不会更新,即使关闭并重新打开它们也不会更新,因为ViewModel实例始终是相同的。
  2. 打开第一个视图后,将实例化所有ViewModel,并从数据库中加载所需的数据。
  3. 我可以想出两种解决这些问题的方法:

    1. 使每个ViewModel实现一个方法,该方法从数据库中读取数据并初始化属性 - 而不是在构造函数中执行此操作。这将需要在每次打开视图时调用该方法。这引入了我不喜欢的temporal coupling
    2. 以每次调用ViewModelLocator上的相应属性时创建所请求的ViewModel的方式实现ViewModelLocator。我不喜欢这种方法,因为我的编写根不会在程序启动时执行,而是会在程序实例的整个生命周期内传播。
    3. 还有其他方法可以解决这个问题吗?别人怎么解决这个问题?

2 个答案:

答案 0 :(得分:2)

  

以每次调用ViewModelLocator上的相应属性时创建所请求的ViewModel的方式实现ViewModelLocator。

这是我通常在这种情况下采取的方法。但是,我没有通过ViewModel的DI组成ViewModelLocator,而是组建了创建ViewModel的工厂。

  

我不喜欢这种方法,因为我的编写根不会在程序启动时执行,而是会在程序实例的整个生命周期内传播。

至少部分地通过使组合物组成工厂而不是类型本身来“解决”。组合在启动时发生一次,但创建可以在所讨论的ViewModel的任何时间发生。

例如,使用MEF,您可以切换导入以直接使用ExportFactory<T>而不是其类型。除了NonShared Creation Policy之外,您还可以根据需要构建ViewModel,并始终使用新数据,而不会出现时间耦合问题。

答案 1 :(得分:0)

我的抽象ViewModelBase基类需要一个抽象的RefreshDataCore()方法。可以通过在ViewModel实例上调用Refresh()或设置IsDirty标志来手动调用此方法。当ViewModel.IsVisible为true且设置了IsDirty时,也会调用Refresh()。

这样,只要您的视图模型可见,您就可以延迟刷新数据,也可以通过调用Refresh()手动调用刷新。

以下示例。 (为简单起见,我已将INPC通知留下了)

public abstract class ViewModelBase
{
     //Pull your data from the repository here
     protected abstract void RefreshCore();
     public void Refresh()
     {
            RefreshCore();
            IsDirty = false;
     }

     private bool _isVisible = false;
     //DataBind this to the visibility of element "hosting" your view model
     public bool IsVisible
     {
         get { return _isVisible; }
         set
         {
              if (_isVisible == value)
                  return;


              _isVisible = value;
              if (IsVisible && IsDirty)
                   Refresh();
         }
     }

     private bool _isDirty = true;
     public bool IsDirty 
     {
         get { return _isDirty; }
         set 
         {
            if (_isDirty == value)
               return;

            _isDirty = value;
            if (IsVisible && IsDirty)
               Refresh();
         }
     }

}