问题
I'm developing a WPF application using the MVVM pattern. I'm using MVVM Light library and I'm also trying to use a dependency injector (I'm considering Ninject and Unity).
I've read a lot of blog articles and I'm quite confused about the "proper" way of making my classes communicate with each other. In particular, I don't know when to use Dependency Injection and when to rely on the mediator pattern.
Lets consider an example. I have a ViewModel, lets call it DataViewModel, and the Data class that provides some kind of data. How is it better to communicate between them:
A. Inject a dependency to DataViewModel with an interface of IData? This way Data will not have to rely on Messenger, but it will have to provide an event if the Data changes, and the ViewModel will have to subscribe to it.
B. Rely on the mediator pattern (implemented in MVVM Light as Messenger) and send messages between Model and ViewModel? This way it will not be necessary to use Dependency Injection at all, because whole communication will be based on messages.
Moreover, should my ViewModels have injected dependencies on other ViewModels, or it would be better just to rely on the Messenger? If the first, would it be necessary to define a separate interface for each ViewModel? I think that defining an interface for each VM will be an additional work, but maybe it is worth it.
回答1:
Generally the ViewModel goes to a Service (as Prism calls it) to retrieve the data it needs. That service is pushed to the ViewModel via DI (Constructor Injection) although you could perform this another way via a ServiceLocator.
Therefore your ViewModel will hold a reference to a service which will abstract away the retrieval of your data. The data could be coming from a DB, XML file, who knows...the abstraction is there. So for your case of IData, the reference to that type will occur at some point in the ViewModel but not by way of any from of DI. If your IoC framework allows it (Prism does) you create mappings of interface types to concrete types and then retrieve those types via your container; such is the case with Unity.
Here is a brief example...Scripts is bound to the View and the ViewModel is injected into the View. Notice the use of the IScriptService to retrieve the data. The data coming back is a collection of IScript types, however we never formally injected that type into the ViewModel because we don't care about the type as a single entity we care about the type on a grandeur scale.
public ScriptRepositoryViewModel(IUnityContainer container, IScriptService scriptService, IEventAggregator eventAggregator)
{
_container = container;
_scriptService = scriptService;
_eventAggregator = eventAggregator;
}
public ICollectionView Scripts
{
get
{
if (_view == null)
{
_view = CollectionViewSource.GetDefaultView(_scriptService.Scripts);
_view.Filter = Filter;
}
return _view;
}
}
When you make your way to the View, the same case can be had there, the View will get injected via DI (Constructor Injection) with the ViewModel. I would not make other ViewModels depend on each other, keep them isolated. If you begin to see a need for coupling take a look at the data you are trying to share, more often then to that data needs to be abstracted out further and not become coupled to any ViewModel.
回答2:
There is more than one good solution to your problem,
I suggest you to use some single interface in your data models, put it in a base class, this interface will allow your data objects to communicate with the outside world.
For the view models inject not the data but an interface that can retrieve data for you, the data will expose events that the vm can register to them after he gets them.
data oject should not know who holds him, view model knows what kind of data he holds but I dont recommend to inject this data due to flexibility issues.
来源:https://stackoverflow.com/questions/4207569/mvvm-communication-between-the-model-and-viewmodels