如何使来自不同屏幕上显示的同一来源的数据保持同步

时间:2012-03-31 01:49:19

标签: c# silverlight mvvm wcf-ria-services mvvm-light

我有一个场景,其中至少有两个屏幕将同时显示,具有相同的来源。在一个屏幕上,此数据是只读的,另一个是可编辑的。我需要在两个屏幕上同步数据。此外,数据可以由不同的用户修改。

让我们说这是一系列行动:

  1. 用户打开一个包含来自collectionA
  2. 的只读数据的screenA
  3. 用户需要向collectionA添加新项目,因此screenB打开
  4. 用户在screenB上添加3个新项目,然后将其关闭
  5. 屏幕上的集合需要有新项目
  6. 可能存在超过2个屏幕包含来自同一来源(集合类型)的数据的情况。

    我使用MVVM light和ViewModelLocator模式将ViewModel暴露给Views。目前我在ViewModel的构造函数中获取数据。这意味着如果我将ViewMOdel实例缓存以供重用,我将只获取一次数据,所有屏幕将使用相同的集合作为源,因此同步自动完成。这也意味着,如果网络上的其他用户更改数据,则新数据将永远不可见,因为数据仅被提取一次(在创建ViewModel期间)。

    另一种方法是ViewModelLocator每次请求时都返回ViewModel的新实例。这意味着始终会获取来自数据库的新数据,因此不再存在更改数据的其他网络用户的问题。但是,在这种情况下,每个ViewModel将包含不同的集合数据实例,因此只会自动同步数据编辑,不会自动添加/删除实体。

    那么,在请求ViewModel时获取新数据的最佳方法是什么,并且还在不同屏幕之间同步数据?

2 个答案:

答案 0 :(得分:1)

由于您使用的是MVVM Light的ViewModelLocator,因此您可能会使用类似

的代码
public class ViewModelLocator
{
    static ViewModelLocator()
    {
        // register your types with your favourite DI container
    }

    public MainViewModel Main
    {
        get 
        { 
            var vm = // resolve singleton instance, data obtained in constructor
            return vm;
        }
    }

这样的简单更改是否足以满足您的要求?

public class ViewModelLocator
{
    ...
    public MainViewModel Main
    {
        get 
        { 
            var vm = // resolve singleton instance
            vm.RefreshData(); // data obtained/updated here
            return vm;
        }
    }

答案 1 :(得分:1)

我在评论中解释了这一点,所以我创建了example我正在谈论的内容。它使用的是CM,但这个想法可以转移到MVVM-light。

我创建了2个视图模型:SharingScreen1ViewModelSharingScreen2ViewModel以及2个视图:SharingScreen1ViewSharingScreen2View

每个VM都会注入SharedViewModel单例。从左侧导航,您可以在2个视图之间切换。 SharedDataViewModel属性最初是在SharingScreen1ViewModel中的OnInitialize方法中设置的。然后单击按钮可以在SharingScreen2ViewModel中更改值。切换回View one,并且值也已更改。

当我提到DispatcherTimer时,我指的是每30秒刷新一点数据的要求。计时器是更新此数据的众多方法之一。正如您在本示例中所看到的,当初始化第一个ViewModel时,数据被设置一次,当用户单击按钮时,数据将在另一个ViewModel中再次设置。

接口SharedViewModel实现:

 public interface ISharedViewModel
    {
        string FirstName { get; set; }
        string LastName { get; set; }
        string Address { get; set; }
    }

SharingScreen1ViewModel:

 [Export(typeof (SharingScreen1ViewModel))]
    public class SharingScreen1ViewModel : Screen
    {
        [ImportingConstructor]
        public SharingScreen1ViewModel(ISharedViewModel sharedViewModel)
        {
            DisplayName = "Shared Data Screen 1";

            SharedViewModel = sharedViewModel;
        }

        public ISharedViewModel SharedViewModel { get; set; }

        protected override void OnInitialize()
        {
            base.OnInitialize();

            SharedViewModel.FirstName = "Jimmy";
            SharedViewModel.LastName = "Hugh";
            SharedViewModel.Address = "555 South St.";
        }
    }

SharingScreen2ViewModel:

[Export(typeof (SharingScreen2ViewModel))]
    public class SharingScreen2ViewModel : Screen
    {
        [ImportingConstructor]
        public SharingScreen2ViewModel(ISharedViewModel sharedViewModel)
        {
            DisplayName = "Shared Data Screen 2";

            SharedViewModel = sharedViewModel;
        }

        public ISharedViewModel SharedViewModel { get; set; }

        public void ChangeSharedData()
        {
            SharedViewModel.FirstName = "New First Name";
            SharedViewModel.LastName = "New Last Name:";
            SharedViewModel.Address = "New Address";
        }
    }