如何与多个ViewModel共享多个ObservableCollections?

时间:2017-09-13 14:15:14

标签: c# .net wpf mvvm prism

我正在编写一个包含4个视图的程序: CompanyView MembersView WeeksView ReportsView 。每个都有一个相应的ViewModel和Model。我使用PRISM BindableBase来创建ViewModels。数据绑定正确。

  • CompanyViewModel 包含公司类型的对象。
  • MembersViewModel 包含会员对象的ObservableCollection。
  • WeeksViewModel 包含对象的ObservableCollection。

通过MainWindow中的顶部按钮执行导航,可以随时选择任何View

Container.RegisterTypeForNavigation<CompanyView>("CompanyView");
Container.RegisterTypeForNavigation<MembersView>("MembersView");
Container.RegisterTypeForNavigation<WeeksView>("WeeksView");
Container.RegisterTypeForNavigation<ReportsView>("ReportsView");

问题是 WeeksViewModel 必须可以访问成员ObservableCollection 。并且 ReportsViewModel 必须可以访问公司 对象成员ObservableCollection Weeks ObservableCollection

我不知道如何实现这一点。如何在ViewModel之间轻松共享数据?

我尝试使用 PRISM IEventAggregator 在更新后发布 ObservableCollections ,这样可行,但必须首先访问View才能收听事件。如果用户之前未点击“周”视图,则更新的 MembersCollection 将无法访问 WeeksView 。我可以预先初始化视图吗?我该怎么做?

我跟随 MVVM Made with Prism - 网络研讨会https://www.youtube.com/watch?v=ZfBy2nfykqY)并发现了评论中写的相同问题。 Brian Lagunas建议解决这个问题的唯一方法是通过导航参数:

  

我有一个小问题,UpdateEvent将消息从ViewAViewModel传递给ViewBViewModel。如果我没有访问ViewB,它似乎不起作用,我认为这是因为ViewBViewModel尚未实例化,直到它的视图已加载至少一次。

     

任何人对此有任何想法,我假设在需要之前实例化所有视图模型是一个坏主意,那么如何在实例化之前将默认信息从其他视图模型中获取到视图模型中?

     
    

Brian Lagunas:唯一的方法是在导航到ViewBViewModel时将该信息作为参数传递。

  

我考虑使用导航参数,但似乎您必须知道从哪里导航到WHERE。例如。来自 MembersView &gt; WeeksView ,将成员集合作为参数传递。但是用户可以按任何顺序进行导航,包括在程序加载时直接进入 WeeksView 。例如如果来自公司视图, WeeksView 如何获得成员集合?公司不了解会员收藏。

我对其他想法持开放态度,我已经进行了广泛的研究并且完全陷入困境: - (

非常感谢您的想法和帮助! 亲切的问候, 达米安

2 个答案:

答案 0 :(得分:2)

  

问题是WeeksViewModel还必须能够访问Members ObservableCollection。 ReportsViewModel还必须能够访问Company Object,Members ObservableCollection和Weeks ObservableCollection。

     

我不知道如何实现这一点。如何在ViewModel之间轻松共享数据?

您可以使用单个视图模型,其中包含每个特定视图模型的属性以及要在两个或多个视图模型之间共享的公共属性,例如:

class MainViewModel
{
    public CompanyViewModel CompanyViewModel { get; set; }
    public MembersViewModel MembersViewModel { get; set; }
    public WeeksViewModel WeeksViewModel { get; set; }

    public ObservableCollection<Members> Members { get; set; }
}

然后,每个子视图都可以继承父窗口的DataContext并绑定到所有视图模型类型中所需的任何属性。

另一种选择是在视图模型之间来回传递信息,使用直接引用,事件聚合器或共享服务。

但是,如果他们仍然必须访问彼此的属性,那么拼命尝试将视图模型之间的逻辑分开似乎毫无意义。所以我可能会采用第一种方法。

答案 1 :(得分:-1)

我建议CompanyObservableCollection<Week>ObservableCollection<Member>来自一个或多个服务。

WeeksViewModel然后从服务接收ObservableCollection<Week>ObservableCollection<Member>并处理数据以供WeeksView使用。由ReportsViewModel消费的Company流程ObservableCollection<Week>ObservableCollection<Member>ReportsView ...如果有人添加Member,他会通过拥有ObservableCollection<Member>的服务以及从该服务收到ObservableCollection<Member>的所有视图模型都会收到通知并相应更新。

不需要在视图模型之间传递数据,因为视图模型不拥有数据。他们所做的只是将某些数据源中的数据转换为要显示的视图,反之则将用户操作转换为对修改数据的服务的调用。

当您查看拥有数据的模型时,您会在视图模型上获得UpdateData之类的方法,最终您最终会得到UpdateThisUpdateThat或一个不可理解的意大利面条代码所有视图都使用mm8风格的巨型视图模型。你不想要那个。