I have searched extensively and have been unable to find any good guidance on how to properly design an application using dependency injection that has multiple layers of view models.
What is the best way to implement dependency injection using something like Unity when you have view models that will need to create view models that will need to create yet other view models?
For example, let's say I have an application with a MainViewModel where I want to be able to show a bunch of different types of data in a tabbed interface a la Visual Studio.
I execute a command to open a collection of User objects using a view model called UsersViewModel. This view model takes a repository IUserRepository in its constructor. A GetAll method on IUserRepository is invoked to get a collection of User objects which are displayed in a grid in the view.
If the details for a specific User object need to be edited, I need to create a UserViewModel that also takes an instance of IUserRepository and the ID of the particular User object in its constructor. A FindById method on IUserRepository is invoked to get the specific User object.
I need to show the User details in a separate tab in the main view. I have a requirement to be able to view/edit the details for multiple User objects simultaneously, so I can't just open the details modally. As such, the UserViewModel needs to be able to persist its own changes since the UsersViewModel could be closed before a particular UserViewModel is saved.
So what is the best way to resolve the UserViewModel instances for this scenario? I could pass an instance of IUnityContainer into UsersViewModel and then use that to resolve them, but from what I've read, that is a bad idea. How else can it be done?
I have set up a MVVM application with Autofac and MEF to solve the problem you are talking about. To make a long story short, I have created a service interface IViewModelProvider which serves ViewModels for arbitrary models. The implementation of this service provides a cache for all ViewModels and creates ViewModels for models if no ViewModels of the requested ViewModel type for a particular model can be found.
The ViewModelProvider is kind of it's own IoC container, which reflects all loaded assemblies at initialization and then resolves the dependencies at runtime. The ViewModelProvider registers an instance of itself for the service IViewModelProvider and thus can pass itself to the ViewModelswhich require the ability to instantiate new ViewModels.
I am very happy with this solution, as I feel like having a neat separation of concerns here. The global ViewModel cache is awesome, because it saves resources and you can actually compare ViewModels for equality, which I come across quite often.
This solution can be simplified by using the same IoC container as for the UI, as you have pointed in your question. I agree that it is not a good idea to pass the IUnityContainer to the ViewModels directly. I can't see anything wrong about using the container for resolving the ViewModels, though. I would recommend to build a simple service, which caches ViewModel instances and creates new ViewModels by using the IUnityContainer.
The following code is pseudo code, mixing a bit of MEF with a bit of Autofac syntax, but I think it get's clear what it's about:
An interface for getting the ViewModels:
public interface IViewModelProvider
{
T GetViewModel<T>(object model);
}
An implementation which imports the Unity container and uses it for resolving ViewModels which have not been cached already. The ViewModelCache is something like an advanced dictionary you have to build yourself.
[Export(typeof(IViewModelProvider))]
public class ViewModelProvider : IViewModelProvider
{
private IUnityContainer _container;
private ViewModelCache _viewModelCache;
[ImportingConstructor]
public ViewModelProvider(IUnityContainer container)
{
_container = container;
}
public T GetViewModel<T>(object model)
{
if (_viewModelCache.Contains<T>(model))
return _viewModelCache.Get<T>(Model);
var viewModel = _container.Resolve<T>();
viewModel.Model = model;
_viewModelcache.Cache(viewModel);
return viewModel;
}
}
then this service can be injected into your ViewModels and the ViewModels can create their own children ViewModels and don't have to care about whether these already exist because or need to be created.
Hope this helps. It's a broad topic, so please ask if you have any particular questions.
Related
I'm over-thinking this and getting myself into a muddle but can't clear my head.
I'm new at WPF and I'm trying to get familiar with MVVM. I understand the theory. I need a view, a model and another model (called the view-model).
However, what happens if my model is constructed by a parameter of the View's constructor.
So, assuming I have a totally empty project, the only thing is I've an overloaded MainWindow constructor which takes the model:
public MainWindow(Logging.Logger logFile)
{
InitializeComponent();
this.DataContext = logFile;
}
The Model is the logFile. Can I still implement the MVVM when I don't have a separate Model class?
Any thoughts would be appreciated.
You're overthinking this.
There are several components to MVVM:
View:
The view provides a, well, view on the data. The view gets its data from a viewmodel
ViewModel:
The viewmodel is there to organise your data so that you can organise one or more sources of data into a coherent structure that can be viewed. The viewmodel may also perform basic validation. The ViewModel has no understanding of the UI so should not contain references to controls, Visibility, etc. A viewmodel gets its data from services.
Services:
Services provide data from external sources. These can be WCF, web services, MQ, etc (you get the idea). The data the service returns may need to be shaped so that it can be displayed in the UI. To do this you would take the raw data from the service and convert it to one or more Model objects.
Model:
A model object is an object that has been created so that it can be easily displayed/work with the UI.
You may find that you don't need to shape your data coming from your services (lucky you), in which case there's no need to create model objects. You may also decided that you don't want your services talking directly to your viewmodels but instead what to have them get their data via a "mediator" object. That's also good in some situations (usually when you're receiving a continuous stream of data from a source/multiple sources).
MVVM is a bit like porridge: there are lots of potential garnishes you can add, but you don't necessarily need to add them all. Or want to.
Does this help?
Edit: just stumbled on this: a more in-depth expression of what MVVM is:Mvvm Standardisation. This may also be useful
The Model is something the ViewModel will know about but not the View. If you need to present info about a Logger, you can certainly have a LoggerViewModel that knows about a Logger, and in turn the View winds up getting to know about the ViewModel. There are several ways to do that, and setting the DC in the view constructor is one of them.
After that basic understanding of who knows about who, what really makes the MVVM architecture pattern, IMO, is that ViewModel communicates to the View via databinding. Nothing more and nothing less. Lots of goodies come out of this, but that is the crux of it that makes it different than other separation of concerns patterns (like Presentation Model, MVP, etc)
That said, you need to get a feel for it by working through some sample projects. Asking questions here on SO is fantastic when you get stuck on something, but you must realize your question here is a bit fuzzy at best. Also, unless you are really looking to present logging info in your view, logging is not an MVVM concern. Its interesting alright but not MVVM.
Google Josh Smith's MVVM demo on MSDN for a perfectly meaty yet approachable beginning sort of project. And ask more questions or refine the one here as they come up!
HTH,
Berryl
forget the view! at least at the beginning ;)
try to think about what you want and what you need. what i understand is that you wanna handle a logfile. so you need a viewmodel for that.
public class LoggerViewmodel{}
you can put the logfile as a parameter to the vm ctor. now you have to think about what you wanna do with your logfile? for everything you want create a property (LastModified, LastRow, whatever) on your viewmodel.
btw there a two different ways to do mvvm, first is view first and the other is viewmodel first. i do both in my projects and take the appraoch wich fits better (viewmodel first the most time ;)) to my needs.
pls edit your questions and add what you wanna do with your logfile, then we can give you a better answer.
edit:
Can I still implement the MVVM when I don't have a separate Model class?
to answer your question the short way - yes you can. you have to seperate the view and viewmodel and use binding to bind the view to the datacontext(viewmodel).
I'm creating a windows 8 application (but I suspect that any one using Xaml can help me). It basically boils down to: a page with a list of products on it, clicking on a product opens a details page.
In my composition root I resolve the view model for the first page, and set the data context appropriately, but I'm not sure what the best practice is for passing a view model to page 2 when the user selects a product.
As far as I can tell I have the following options:-
The first viewmodel requires an abstract factory capable of creating
a view model for page 2 with a .create(product) method, this would be passed in to the first view models constructor
Have the second view model implement an interface with an product property allowing me to use property injection, and pass the second view model as a parameter to the first viewmodel.
Create a service locator which I know is considered by many to be an anti-pattern.
I'm at a bit of a loss, but I suspect the abstract factory is the right way to go, I want to get this right as the object graph is actually this (product->Step->Instruction), so any re-work could take quite a bit of time, but it basically means that my view model if I went down the abstract factory route would take three abstract factories, and the service for getting the initial list of products (and then is this a code smell given how many parameter it has!).
In the situation where you want to resolve the view-model in runtime (from code) factory is the way to go.
To make it easier I would also consider using some DI framework. I believe there won't be many of them for WinRT but autofac is supposed to work with metro.
Dependency Injection might be the way to do it if you are building something big. Personally I usually just pass the parameters in the Navigate() call and initialize the view model using these parameters in the OnNavigatedTo handler.
I've read on msdn that it is common for Models in MVVM to implement interfaces such as ObservableCollection<T>, INotifyPropertyChanged, and IDataError.
My question is around why this is done at the model level and not the ViewModel level. I would expect that a "pure" Model would not have any notification logic, just data and business logic. My first impression is that the VM would wrap the Model's properties and take care of the notifications.
I readily admit that implementing these interfaces in the Model may make implementation easier in many cases, but I'm looking for an explanation as to why the model should be responsible for notifications.
INPC is part of the Core framework unlike say ICommand and DependencyObject which belong to WPF specifically. There was a similar question regarding exposing IQueryable from the service layer. Just like INPC, IQueryable is a core framework class. Not using either of them in an effort to create a pure model is overkill.
Even worse it causes duplication (making the VM wrap expose properties just to add a propertychanged notification).
Observable Collection on the other hand is a different beast. Usually collections in a domain model represent entity relations. In many cases, you don't have control over their instantiation. There's a tradeoff to be made there
Depending on your application, you might have multiple Views and ViewModels of the same data. Say you have one window that shows a list of items with read-only details, but in another window you have the ability to add, edit, and remove items.
If the Model uses ObservableCollection and INotifyPropertyChanged, the changes made in the editable View/ViewModel will be seen and updated in the non-editable View/ViewModel.
Furthermore, if the non-editable View is simple enough, it can be possible and acceptable to simply expose and bind directly to the model. As there is no ViewModel to handle the notification, the Model would need to do the job itself.
I'm using strongly typed views and autofac for Dependency Injection under ASP.NET MVC2 and I'm trying to get a common dynamic header via dependency injection. I.e. i want this to happen without the view having to be away of this content even existing and i was hoping to avoid static discovery of the container and manual resolution, but I can't find a way to easily inject the master or a partial view included in the master via either ctor or property injection.
I can't imagine this is an uncommon task, but all I can find in terms of methods is Controller subclassing to stuff data into untyped ViewData, subclassing ViewModels to stuff master data into the model, or static resolution, all of which I'd prefer not to use. What am I overlooking?
EDIT: As has been pointed out DI into master pages is fighting the framework. So my question is badly framed: I don't really care about DI into master pages, but I have a dynamic element in the chrome of the site, i.e. the master page. Providing it with a model shouldn't be the responsibility of each controller using that master, as it is request context, not controller context specific. I fully admit that injection directly into master pages is inappropriate. If i could register a separate master controller to be invoked in addition, that would be even better. Is that possible? Given this task of providing the master with a model independent of the controller, what is the framework appropriate approach? Or does shared content in MVC require that each Controller has to know about that content?
You could use child actions.
Controller:
public class MyHeaderController: Controller
{
private readony IRepository _repository;
public MyHeaderController(IRepository repository)
{
_repository = repository;
}
[ChildActionOnly]
public ActionResult Index()
{
var model = _repository.GetSomeModel();
return PartialView(model);
}
}
And somewhere in your master page include it:
<div><%= Html.Action("Index", "MyHeader") %></div>
Your problems stem from confusing the term Dependency Injection, and fighting how the ASP.NET MVC framework works.
Also, you are using the term Dependency Injection in the wrong context. You are trying to use a hammer as a chisel.
MasterPages and views in ASP.NET MVC are intended to be used as templates. As stated in the other answer, child actions will solve your problem.
For future reference:
Dependency Injection refers to a means to configure what parameters to inject into class constructors, and have this done for you automatically, overriding some of the frameworks defaults. The purpose for this is to decouple components, so that they become more reusable, more testable, more unitary, amongst other good things.
DI refers to, and solves, a code issue, not a UI issue.
What you are trying to do is simply not possible. Ie, inject via constructors and properties a "dependency" into a masterpage. Again, MasterPages are intended by ASP.NET MVC to be used as just templates. They have no code behind class to instantiate via a constructor that would allow dependencies to be injected into it.
In other words, you are fighting the framework, which means you don't understand it.
If this sounds like nitpicking, I think this has to be highlighted as otherwise, you are confusing yourself and others who read this thread in the future.
Guess we have simple model, e.g. let it be a Person { Name, Age }.
Now we want to display a list of persons.
Persons are read-only
We don't need to edit them
We don't need any additional stuff like presentation properties, etc.
Now question is if it is a good practice do not create PersonViewModel class that will probably be a copy of model class or will delegate all its properties? Is it a good idea to simply bind listbox to list of persons, not to their view models? It looks DRY enough, but what about idea of MVVM?
I have no issue with bypassing the VM and using the M directly in the View. Sometimes the models are so small and static that loading them into a wrapping VM is wasteful.
I've created standalone ViewModels, but generally not standalone models. The reason for this is DataBinding -- most POCOs don't implement the INotifyPropertyChanged interface and adding them in to make them pseudo-Models seems to defeat the purpose of re-using a simple class AND respecting the MVVM pattern.
Now, if you KNOW you're never going to be editing them, it may not be a bad idea. A VM with simple property redirects seems a bit pointless to me.
As far as I'm concerned, if you implement INotifyPropertyChanged, then it becomes a ViewModel, and you can bind to it. :) When I wrote SoapBox Core which is all MVVM, I took the approach that everything is a ViewModel. The only Model objects were classes from third party libraries that I brought in and wrapped in a ViewModel of my own.
I wouldn’t create a ViewModel for the Person business object when the ViewModel doesn’t introduce new required functionality.
You might be interested that there is a second approach in the MVVM community: Create a ViewModel per View and not per Business Object.
Sample applications that follow this approach can be found on the WPF Application Framework (WAF) website.