In my WPF MVVM application I use dependency injection container. When I want to retrieve some data from my Model, I use an asynchronous interface to query the Model and fill the ObservableCollection in my ViewModel (I understood it thanks to the answers to my previous question).
I'm looking for a best solution to handle a following situation. There is a collection of objects I'm retrieving asynchronously from my Model. I want to use the same data to build observable collections in two different ViewModels, as I want to display that data in two different windows. The Model domain objects are going to be wrapped in different ViewModel objects as the wrappers needs to prepare the domain objects to be displayed. I don't want to retrieve data from the Model separately in each ViewModel, but to do it once, as it might be a time-consuming operation.
I've seen a few examples and everywhere a single ViewModel is responsible for retrieving data from the Model service. What should I do to use the once retrieved data in more than one ViewModel?
I think that I should introduce another layer of abstraction between my Model and ViewModels that will handle the caching of retrieved data and every ViewModel that wishes to utilize this data will have the dependency to this layer.
Is this a good idea?
That missing link would be a service as referenced within Prism.
The model classes are typically used
in conjunction with a service or
repository that encapsulates data
access and caching.
You'll note in the previous question that I am making use of a service within that ViewModel.
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;
}
}
Note the IScriptService being injected into the ScriptRepositoryViewModel. That service actually implements caching and varying logic so that whoever polls for the Scripts will get a cached copy or perhaps a fresh copy; the consumer doesn't need to care.
In your instance with your two ViewModels needing the same data you could follow the same pattern of injecting a service into each ViewModel. When the ViewModel calls the service to retrieve the data you can implement logic to not fetch the data from the back end unless it has been stale for 10 minutes or whatever behavior you so desire. It has been abstracted at that point and you are free to do what you need; allowing N ViewModels to consume the data form a central location without un-needed load.
Yes you have to introduce another layer, irrespective of caching or not in my applications ViewModels are used for sole purpose of binding to Views and they don't contain any logic of retrieving data from Business (Service) layer
Use RegionManager["nameRegion"].context, the ViewModel is the context of the View, that yo can share with other ViewModels
Related
I'm relatively new to WPF and MVVM and i am trying to understand how to use commands correctly when they have dependencies in more than 1 view model.
A couple of examples:
In my current application i have a RelayCommand which causes a save action to occur in a couple of different view models (they write a couple of different files). Currently i am handling this using a the mvvmlight messenger to send a message to those view models to get them to do the save which i think is the correct way to do it as it avoids having to provide some kind of delegate or event to/on those view models.
I have a RelayCommand in a view model that has a CanExecute method which relies on the state of 2 other view models. I've currently handled this via the mvvmlight messenger as well by having changes in the view models the CanExecute method depends on message that their state is now valid for the operation. This seems messy but the only alternative i could think of was to use a delegate or event effectively weaving the view models together which i believe i should be avoiding.
Is there some generally accepted way to deal with this which i am missing?
In general your view model layer should have a 1:1 relationship with your view, there should be no good reason for a "Save" function to exist in a view model which is then called by another view model.
What it sounds like you should be doing is putting that logic into a service i.e. something like this:
public interface ISerializationService
{
void Save(SomeData data);
}
Then you need an implementation for this service that does the actual work:
public class SerializationService : ISerializationService
{
void Save(SomeData data)
{
// actual save happens here
}
}
Your view models should then contain properties that point to instances of these services:
public class MyViewModel : ViewModelBase
{
[Inject]
public ISerializationService SerializationService { get; set; }
// called when the user clicks a button or something
private void ButtonClickCommand()
{
this.SerializationService.Save(this.SomeData);
}
}
The only question remaining is "What sets the value of SerializationService?", and for that you need a dependency injection framework. There are plenty out there, MVVMLight installs one itself, but Ninject is the de-facto standard. When implemented properly the injection framework will create all view models for you and then "inject" the dependencies, i.e. your SerializationService property, of type ISerializationService, will be initialized with an instance of your SerializationService class (which in a case like this will also be configured to be a singleton).
Dependency Injection takes a bit of work to get your head around but once you start using it you'll never look back. It facilitates complete separation-of-concerns whilst alleviating the need to pass pointers to everything all up and down your architectural hierarchy.
I am working on a project using PRISM where I have left navigation implemented as Tree View and any click event happens raise event using event aggergation to Enrolment Module which has multiple view model for multiple views (like Wizard Applicaiton where you can go through many views to collect data). I want to have a common or shared or singleton model which can be passed across this view models and save at the end.... users can click on any link any navigation at any time and it should save data in to this singleton model expsosed through different view model. Do you have any samples which are doing something like this... or can you type up a quick one on how to do it? OR it is not possible to do it at all. I am following all patterns from Brian Lagunas's Pluralsight Video for PRISM so try to use that way....
I would have a MasterViewModel which controls the "wizard" pages and current state
It would contain the following properties:
List<ViewModelBase> Pages
int CurrentPageIndex
ViewModelBase CurrentPage, which returns Pages[CurrentPageIndex]
MyClass DataObject
The MasterView that goes with the MasterViewModel would be nothing more than a ContentControl with it's Content bound to CurrentPage. I would probably also define DataTemplates in the MasterView which tells WPF which View to draw with which Page
Your MasterViewModel would be in charge of handling the pages, and passing each page a reference to the data it needs. For example in the constructor it might say,
public MasterViewModel(MyClass dataObject)
{
DataObject = dataObject;
Pages.Add(new InfoPage(DataObject));
Pages.Add(new AddressPage(DataObject.Addresses));
Pages.Add(new PhonePage(DataObject.Phones));
Pages.Add(new SaveMyClassPage(DataObject));
CurrentPageIndex = 0;
}
I have an example here if you're interested
I don't know, is it prism way, or something another, when I build something like wizard, first of all I create instance of all data which wizard collect.
public WizardData wd = new WizardData();
Then, every page of wizard are initialized by this wd instance, i.e.
public FirstWizardPage(WizardData wd)
{
this.wizardData = wd;
}
So, this way allow you to have button Finish on every page, for example. You can initialize your ViewModel with wd, or its properties.
This way is not the best. Its hust one of the possible way.
Another - is to create singleton and use it without reference passing from page-to-page.
When you use Prism you also have a Dependency Injection Container, usually Unity or MEF. To solve your problem you can register your model as singleton to those DI containers. Every view model that asks the DI container to resolve their dependecy, in our special case the model, will get the singleton instance back from the DI container.
Unity example: You register your model as singleton instance:
public void Initialize( )
{
container.RegisterInstance<Model>(new Model(), new ContainerControlledLifetimeManager( ));
}
Now you can resolve your dependencies in your view model:
public ViewModel(IUnityContainer container)
{
Model model = container.Resolve<Model>();
}
Following WPF MvvmFoundation, linking the View with the ViewModel has many choices like described on http://www.paulstovell.com/mvvm-instantiation-approaches.
However their example has nothing about how to link the ViewModel with the Model.
Traditionally I created the model first and then one or more views that render it. It seems that MVVM pushes people to create the View, which creates the ViewModel, which create the Model. I hope it's not the case as wiring a complex business model with various ModelView can else be tough.
How do you instantiate your business model classes in MVVM and link them with your ViewModels?
I normally pass Model objects as constructor params to VM. I use App class as the controller which will initialize MainWindow, MainWindowViewModel with the main model. There after the MainWindowViewModel takes care of initializing other VMs with appropriate model objects.
private void Application_Startup(object sender, StartupEventArgs e)
{
mainWindow = new MainWindow();
mainWindow.DataContext = new MainWindowViewModel(new Model());
mainWindow.Show();
}
You create your BusinessModel classes inside your ViewModel.
So in your CustomerViewModel you would say this.CurrentCustomer = new CustomerModel(), and your CustomerView would bind to the CurrentCustomer property on the ViewModel
If you are interested, I wrote up a simple sample using MVVM as an example of how the View, Model, and ViewModel interact.
I use dependency injection/MEF to do this. Just export all of my model classes all the way down the chain, and have them imported for me automatically into the ViewModel constructor.
I take a variety of different approaches depending on the situation. I've found that when it comes to getting this data linked, one size does not fit all.
For simple cases, I will have the ViewModel and the Model be the same thing. Obviously not that good for all cases, but sometimes there is just no need to go the extra mile to split the M from the VM. (Great for cases where you have, say, listbox items that have scant information)
Sometimes, especially when the model is a chunk of code you don't have access to (written by another developer) it is easy to subclass the model, and add all of your VM things (observable properties, etc.) on to it.
Lastly, I will use the approach that is mentioned by Souvik. Construct the VM with the model information that you want to use as a parameter, or allow it to be passed in otherwise. This is probably the most common approach for my larger and more complex Model / ViewModel relationships.
I am auto-passing IRepository instance to VM constructor using IoC container and everything VM needs to do with models is done via this repository. Repository is class which: Create, read, update and delete data. When I need to show some view (window), I use IViewService.ShowDialog(viewModel As ViewModelBase). In implementation of IViewService, there are views registered with VMs, so VMs only need to know other VMs and not their views (like "Show me view for this view model").
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.
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.
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.
In our application we have many Model objects that have hundreds of properties.
For every property on the model:
public string SubscriptionKind { get; set; }
...100x...
we had to make an INotifyPropertyChanged-enabled property on the ViewModel:
#region ViewModelProperty: SubscriptionKind
private int _subscriptionKind;
public int SubscriptionKind
{
get
{
return _subscriptionKind;
}
set
{
_subscriptionKind = value;
OnPropertyChanged("SubscriptionKind");
}
}
#endregion
...100x...
which meant that when our View sent the Save event, we had to remap all these values of the view model back into the model:
customer.SubscriptionKind = this.SubscriptionKind
...100x...
This became tedious and time-consuming as the models kept changing and we had to map all changes up into the ViewModels.
After awhile we realized that it would be more straight-forward to just connect the DataContext of the View directly to the Model which enables us to bind the XAML elements directly to the Model object properties so that the save event would simply save the object without any mapping whatsoever.
What we lost in this move is:
the ability via UpdateSourceTrigger=PropertyChanged to do fine-grained validation and manipulation in the ViewModel Property Setters, which I really liked: this we don't have anymore since any change in XAML simple changes the dumb property on the Model
the ability (in the future) to create mock views which test our viewmodel's UI logic in a novel way, e.g. "if property SubscriptionKind is set to "Yearly" then (1) change discount to 10%, (2) run "congratulations animation", and (3) make order button more prominent.
Both of these approaches have obvious advantages, e.g. the first way "View-direct-to-Model" approach especially when combined with LINQ-to-SQL is pragmatic and enables you to produce useful software fast, and as long as you use {Binding...} instead of x:Name you still have the ability to "hand off your views to a Blend Designer".
On the other hand, although MVVM requires you to maintain tedious mapping of Model to ViewModel, it gives you powerful validation and testing advantages that the first approach doesn't have.
How have you been able to combine the advantages of these two approaches in your projects?
Since your ViewModel has access to the model, you can also just directly wrap the model's properties:
#region ViewModelProperty: SubscriptionKindprivate
// int _subscriptionKind; - Use the model directly
public int SubscriptionKind
{
get
{
return this.Model.SubscriptionKind;
}
set
{
if (this.Model.SubscriptionKind != value)
{
this.Model.SubscriptionKind = value;
OnPropertyChanged("SubscriptionKind");
}
}
}
#endregion
The advantage here is you can keep your validation in place in the ViewModel if you wish, and have more control over how it's set back to your model, but there is less duplication in place.
Why not use a mapping tool like AutoMapper? It's speedy and you don't have to write all of that mapping code:
Mapper.CreateMap<MyModel, MyViewModel>();
MyViewModel vm = Mapper.Map(myModelInstance);
Really easy and now you get the best of both worlds.
Automapper uses a technique that generates assemblies on the fly to do the mapping. This makes it execute just as fast as if you had written all of that tedious mapping code, but you don't have to.
Since my model objects are business objects, not directly related to the datamodel, I use them directly in the ViewModel.
The first mapping (datamodel to business object model) and the creation of properties are generated by a code generator.
I used a t4 Generator class to create my ViewModels from XAML not sure if this would help your situation.