MVVM:在ViewModel之间共享数据

13

我该如何在多个ViewModel之间共享数据?

例如,应用程序中有一个名为Project的类。

    public class Project : ModelBase
{
    private string _projectName;

    public string ProjectName
    {
        get { return _projectName; }
        set
        {
            _projectName = value;
            RaisePropertyChanged(() => ProjectName);
        }
    }
}
在多个ViewModels应用程序中,应该访问ActiveProject。如何在ViewModels之间共享Project是最好的方式?
  • 中介者模式?(消息传递)
  • 静态对象
  • Singleton模式(如果是,则如何?)
我以前使用过消息传递,但需要编写大量代码。对于所有ViewModels,我必须创建ActiveProject属性,并且还必须注册一个messenger来更新它。
我使用MVVM Light框架。
任何代码示例都将不胜感激。

你的 ActiveProject 是由其中一个视图模型在某个地方创建的吗?如果是这样,那么消息传递可能是最好的选择(而且它并不是那么冗长)。另一个选项是将 ActiveProject 注入到每个需要它的视图模型中,同时将 ActiveProject 的生命周期设置为单例在所选择的 IoC 容器中 - 这是你提出的第三个选项...但到目前为止,这主要是我猜测。 - Patryk Ćwiek
2
@TrustMe-I'maDoctor 为什么我们 WPF 开发者总是把一切都复杂化?将其存储在 App 类中作为静态属性不是更容易吗? - Federico Berasategui
@HighCore 那总是一个选择... 但静态读写属性让我感到不舒服,太容易被滥用了。 :) - Patryk Ćwiek
@Trustme-I'maDoctor 使用依赖注入技术会很好。请给我一个与我的问题相关的示例或样本链接。 - Unforgiven
@Unforgiven 例如,SimpleInjector可以自动解析具体类型,但您也可以执行container.RegisterSingle<Project>(() => new Project());,然后仅在构造函数中请求Project activeProject。其他IoC容器还支持命名注入,因此您也可以使用它。 - Patryk Ćwiek
5个回答

7
我会创建一个ViewModel,作为所有项目ViewModel的母版(我们称其为Solution)。
Solution ViewModel将拥有ActiveProject属性和一个Projects的可观察集合。

2
但是...如果您有一个视图的多个视图模型,那么如何绑定此共享属性? - inside
1
@inside - 这里有一个顶层的ViewModel,它被分配给View的DataContext。其他的ViewModel是这个顶层ViewModel的属性,可以通过指定相对于顶层ViewModel的绑定路径进行绑定。 - Emond
3
我用了一种略微不同的方法来解决这个问题。我有多个视图模型,它们都共享同一个ViewModelBase类,在ViewModelBase中,我有一个“Projects”列表的单例,然后在我的视图中,我只需将绑定路径指定为childVM.Projects,这样无论是哪个vm,它们都将共享同一个Projects实例。这使我可以在每个DataContext中拥有多个视图模型,并且没有任何歧义存在。 - inside
5
“单例模式-永远是首选解决方案”,没有任何程序员会这么说 :D。 - Gusdor
2
还有呢?这太模糊了! - AndyUK

6
我建议使用中介者模式。我以前在VM之间使用事件聚合器进行此类消息传递,而且实际上没有太多的工作要做。

2
这真的应该成为被接受的答案。此外,似乎遇到这种反模式的人只构建了两层应用程序,而没有将模型作为第三层。 - Scott Nimrod

4

不要,不要。在你的MVVM应用程序中不要以这种方式使用单例。实际上,Project类应该是ViewModels的模型。只需将其传递给vm的构造函数即可。如果您确实需要在多个vm中共享一个Project类的实例,则可以在构建视图模型时使用工厂和某些类型的缓存。如果您的vm需要更多信息,请创建特殊的Model类,该类将派生自Project(或实现IProject),因此您可以轻松使用接口隔离原则。


1

单例模式肯定会有所帮助。要实现这一点,如果我有一个名为User的类:

    private static User mInstance;

    private User () //constructor
    {
    }

    public static User Instance
    {
        get
        {
            if (mInstance == null)
                mInstance = new User();
            return mInstance;
        }
    }

1
你可以拥有一个静态集合,让你的视图模型在导航到新的视图模型之前填充它。目标视图模型可以从其构造函数中检索数据。
例如,ViewModel1(VM1)将创建一个Project并填充它。 VM1将然后把Project放入共享的静态集合中。 然后,VM1将导航到另一个视图模型(VM2)。 在VM2的构造函数中,您将访问集合,并检索由VM1放置在其中的Project。
如果您使用键值对字典,还可以允许您在视图模型之间共享其他数据。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接