多个视图模型通过通知共享服务

Multiple viewmodels sharing a service with notification

问题:我有两个视图模型与一个列表共享一个服务。我的问题是如何设置通知,以便两个视图模型都知道此列表何时更改。下面的描述和我所在位置的代码。

我发现这个示例 HERE 看起来很适合我正在尝试做的事情,但我有一个关于如何在我的视图模型中收到服务更改通知的问题。我将添加一些我模拟过的代码,看看我是否在正确的轨道上。我正在使用 WPF/MVVM Light。

第一部分是具有接口的服务,该接口将包含数据列表,在本例中我使用的是字符串列表。我希望两个视图模型中的 属性 都可以访问此数据列表,并在更改时收到通知。我认为让我感到困惑的是我的视图模型中的 IOC 接口。我越来越理解为什么这是好的,但我仍然在思考它,我不确定如何在服务中更改列表时设置通知。如果我的服务没有被注入,我可能已经设置了一个事件或 属性 我的视图模型 属性 将访问 get/set 但注入我的服务不会暴露我的 public 字段,只是方法.这对我来说是新的,所以很可能我没有正确理解或遗漏了什么。

我在我的服务中使用了一个列表而不是一个 ObservableCollection,这是基于我已经警告不要在这里使用 ObservableCollection 的一些阅读。感谢您的帮助。

public class MyService : IMyService
{
    private List<string> myList = new List<string>();

    public List<string> getMyList()
    {
        return this.myList;
    }
    public void setMyList(List<string> value)
    {
        this.myList = value;
    }
    public void addValue(string value)
    {
        this.myList.Add(value);
    }
    public void insertValue(int index, string value)
    {
        this.myList.Insert(index, value);
    }
}

public class MyViewModelOne : ViewModelBase
{
    private readonly IMyService myService;

    public MyViewModelOne(IMyService myService)
    {
        this.myService = myService;
    }

    public List<string> MyProperty // control item source will bind to this
    {
        get
        {
            return this.myService.getSource();
        }
    }
    public void setSomeValue(value)
    {
        this.myService.addValue(value);
    }
}

public class MyViewModelTwo : ViewModelBase
{
    private readonly IMyService myService;

    public MyViewModelTwo(IMyService myService)
    {
        this.myService = myService;
    }

    public List<string> MyProperty // control item source will bind to this
    {
        get
        {
            return this.myService.getSource();
        }
    }
    public void setSomeValue(value)
    {
        this.myService.addValue(value);
    }
}

好的,让我尝试阐明这一点。首先,变更通知并不是为了在view model之间传递信息,而是通知view本身view model的a属性发生了变化

视图模型向视图发出更改通知的方法有以下几种:

  1. INotifyPropertyChanged界面
  2. INotifyCollectionChanged界面
  3. 属性 名称后缀为 Changed 的自定义事件(例如,名为 MyPropChanged 的事件对应名为 MyProp 的 属性)

说了这么多,一个视图模型还是可以订阅上述方法产生的事件的,如果你真的需要,当然可以。

编辑:

检查此 link 以获得对上面第 3 项的描述。

根据我对您的问题的了解,您本质上需要的是您的服务级别的 INotifyPropertyChanged 实现以及我的列表列表是从服务注入的 ObservableCollection。

现在,如果有通知更改,它将直接在服务上进行,因此不需要明确处理。

您的绑定可能看起来像 "{Binding MyService.MyProperty}"

我以两种不同的方式实现了这一点,我选择了第一个示例,因为我认为它更容易在代码中遵循。

出现这个问题是因为我在主视图中有一个控件,其中的相关代码在增长,我意识到我想要在一个单独的视图中使用相同的 control/behavior,该视图将使用相同的 data/control不同的目的。 我不想在两个地方复制这个 control/template/code 所以我把它变成了一个用户控件。然后我将用户控件嵌套在我的视图中。用户控件有它自己的虚拟机。主视图用新数据更新服务,嵌套控件侦听事件以了解何时有新数据。

对 MVVM 思维仍然很陌生,所以请随时指出这些示例中的任何问题。

使用带有事件处理程序的服务的示例。

public interface IMyInterface
{   
    event EventHandler OnSomeEvent;
    void addSomeData(string value);
    void getSomeData();
}

public class MyInterface: IMyInterface
{
    public event EventHandler OnSomeEvent = delegate { };  

    public void addSomeData(string value)
    {
        // do stuff
        OnSomeEvent();
    }
    public string getSomeData()
    {
        return "some data";
    }
}

// Main ViewModel
public class ViewModelOne : ViewModelBase
{
    IMyInterface myInterface;
    public NotifyViewModel(IMyInterface myInterface)
    {
        this.myInterface = myInterface;
        this.myInterface.OnItemSourceChanged += myInterface_OnSomeEvent;
    }

    void testEvent()
    {
        this.myInterface.addSomeData("test data");
    }
}

// My nested user control
public class ViewModelTwo : ViewModelBase
{
    IMyInterface myInterface;
    public NotifyViewModel(IMyInterface myInterface)
    {
        this.myInterface = myInterface;
        this.myInterface.OnItemSourceChanged += myInterface_OnSomeEvent;
    }

    void myInterface_OnSomeEvent(object sender, System.EventArgs e)
    {
        // do stuff
    }
}

使用 MVVM Light Messaging 的示例

public class EventDataSource
{
    public string MyItemSource { get; set; }
    public EventDataSource()
    {
        MyItemSource = string.Empty;
    }

}

// Message class
public class MyDataSourceMessage : MessageBase
{
    public EventDataSource MyItemSource { get; set; }
    public MyDataSourceMessage(EventDataSource myItemSource)
    {
        MyItemSource = myItemSource;
    }
}

// Main ViewModel
public class ViewModelOne : ViewModelBase
{
    public NotifyViewModel() {}

    void testMessage()
    {
        EventDataSource msg = new EventDataSource() { MyItemSource = "magic message!"};
        Messenger.Default.Send(new MyDataSourceMessage(msg as EventDataSource));
    }
}

// My nested user control
public class ViewModelTwo : ViewModelBase
{

    public NotifyViewModel()
    {
        Messenger.Default.Register<MyDataSourceMessage>(this, (action) => ReceiveMessage(action));
    }

    private ObservableCollection<string> myProperty = new ObservableCollection<string>();
    public ObservableCollection<string> MyProperty
    {
        get { return myProperty; }
        set
        {
            myProperty: = value;
            RaisePropertyChanged(() => MyProperty);
        }
    }
    void ReceiveMessage(MyDataSourceMessage action)
    {
        // do something with the data
        MyProperty.Add(action.DGItemSource.ItemSource);
    }
}