I believe one of the main benefits of MVVM is decoupling, the binding and lack of references makes things a lot more reusable.
All MVVM examples I find have some kind of View with a ViewModel with the same naming like ExampleView
has a ExampleViewModel
. And always a one to one relationship, one View, one ViewModel.
But in my current project I have a form to be filled so data can be added to the data base, also the user has the option to edit the data on the data base, so this form View can be used transparently with two different ViewModels, one for adding data and one for editing data. I find it a little stupid to copy and paste and entire View just to have it named after its ViewModel, and not only that, if I need to change something, it will always have to be twice the work and stuff might be forgotten.
Some frameworks have a ViewModel locator that will use this same naming convention to bind the View with the ViewModel automatically, and this makes me question the reusability of Views with many different ViewModels.
My question basically is: Is it there a problem in using one View with different ViewModels? Is it bad practice? Are there any naming conventions to this particular situation?
The lack of examples on reusability makes me question the validity of this practice.
There is no problem - the view is knowledgable of the view model but not vice versa. This is fine with what you're doing.
I would however create an interface of the common binding properties in both view models then a view model locator to expose the instance as a property. That means your binding to the implementation but don't care which one.
How you toggle that implementation depends on how you instantiate your view.
As said in kidshaw answer:
Assuming that NewExampleViewModel
and EditExampleViewModel
share the same IExampleViewModel
interface (whose properties are referenced by the view) and you strict don't want violate encapsulation, you can do it as:
var view = new ExampleView();
...
var NewVM = new NewExampleViewModel(...);
...
view.DataContext = NewVM;
...
(or)
var EditVM = new EditExampleViewModel(...);
view.DataContext = EditVM;
...
Note that you can't use IExampleViewModel
as DesignInstance
in the view, as:
<UserControl ...
d:DataContext="{d:DesignInstance Type=vmi:IExampleViewModel}"
to do that you need a concrete type, so you don't have IDE support in define the bindings.
You could use NewExampleViewModel
or EditExampleViewModel
as DesignInstance
only while designing the view so to have IDE binding support, then remove it for the encapsulation principle.
Perhaps you should use a user-control instead of a view.
You can then embed a user-control into your views.
A user-control is not intended for view-model binding.
It's intended to be plugged into other containers.
In your case, you have different uses for this control based on the state of your business model.