MVVM:Model和ViewModels之间的通信

时间:2010-11-17 18:04:36

标签: wpf dependency-injection mvvm-light mediator

我正在使用MVVM模式开发WPF应用程序。我正在使用MVVM Light库,我也在尝试使用依赖注入器(我正在考虑使用Ninject和Unity)。

我已经阅读了很多博客文章,我对让我的课程彼此沟通的“正确”方式感到很困惑。特别是,我不知道何时使用依赖注入以及何时依赖于介体模式。

让我们考虑一个例子。我有一个ViewModel,我们称之为DataViewModel,以及提供某种数据的Data类。 如何在他们之间进行沟通更好:

一个。使用IData接口向DataViewModel注入依赖项?这样数据就不必依赖于Messenger,但如果数据发生变化,它必须提供一个事件,而ViewModel必须订阅它。

B中。依赖于中介模式(在MVVM Light中实现为Messenger)并在Model和ViewModel之间发送消息?这样就根本不需要使用依赖注入,因为整个通信将基于消息。

此外,我的ViewModel是否应该在其他ViewModel上注入依赖项,或者仅仅依靠Messenger更好?如果是第一个,是否有必要为每个ViewModel定义一个单独的接口?我认为为每个VM定义一个接口将是一项额外的工作,但也许值得。

2 个答案:

答案 0 :(得分:4)

通常,ViewModel转到服务(如Prism所称)以检索所需的数据。该服务通过DI(构造函数注入)推送到ViewModel,尽管您可以通过ServiceLocator以另一种方式执行此操作。

因此,您的ViewModel将保留对服务的引用,该服务将抽象出您的数据检索。数据可能来自DB,XML文件,谁知道......抽象就在那里。因此,对于IData的情况,对该类型的引用将发生在ViewModel中的某个点,而不是来自DI中的任何一个。如果您的IoC框架允许它(Prism确实如此),您可以创建接口类型到具体类型的映射,然后通过容器检索这些类型; Unity就是这种情况。

这是一个简短的示例...脚本绑定到View,ViewModel注入View。注意使用IScriptService来检索数据。返回的数据是一组IScript类型,但是我们从未正式将这种类型注入到ViewModel中,因为我们并不关心类型作为单一实体,我们关心宏大规模的类型。

        public ScriptRepositoryViewModel(IUnityContainer container, IScriptService scriptService, IEventAggregator eventAggregator)
        {
            _container = container;
            _scriptService = scriptService;
            _eventAggregator = eventAggregator;
        }

        public ICollectionView Scripts
        {
           get 
           {
               if (_view == null)
               {
                   _view = CollectionViewSource.GetDefaultView(_scriptService.Scripts);
                   _view.Filter = Filter;
               }

               return _view;
           }
       }

当您前往View时,可以使用相同的案例,View将通过DI(构造函数注入)与ViewModel一起注入。我不会让其他ViewModels相互依赖,让它们保持孤立。如果您开始看到需要耦合,请查看您尝试共享的数据,然后更频繁地需要将这些数据进一步抽象出来,而不是与任何ViewModel耦合。

答案 1 :(得分:1)

您的问题不止一个很好的解决方案,

我建议你在数据模型中使用一些单一的接口,把它放在一个基类中,这个接口将允许你的数据对象与外界通信。

对于视图模型,不是注入数据而是注入可以为您检索数据的接口,数据将公开vm在获取数据后可以注册的事件。

数据对象不应该知道谁拥有他,视图模型知道他持有什么样的数据但是我不建议因为灵活性问题而注入这些数据。