多个视图模型通过通知共享服务
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属性发生了变化
视图模型向视图发出更改通知的方法有以下几种:
INotifyPropertyChanged
界面
INotifyCollectionChanged
界面
- 属性 名称后缀为
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);
}
}
问题:我有两个视图模型与一个列表共享一个服务。我的问题是如何设置通知,以便两个视图模型都知道此列表何时更改。下面的描述和我所在位置的代码。
我发现这个示例 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属性发生了变化
视图模型向视图发出更改通知的方法有以下几种:
INotifyPropertyChanged
界面INotifyCollectionChanged
界面- 属性 名称后缀为
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);
}
}