Here is the simple question: what do you use to link your views to your view models?
Basically there is 2 common ways of achieving that, data templates and view model injection (samples below).
What I would like to know is why do you prefer a method over the other and in which case you use them. Precise the MVVM framework you use.
The data template way or "View Model first" approach (Resources.xaml):
<DataTemplate DataType="{x:Type my:PersonViewModel}">
<my:PersonView/>
</DataTemplate>
The view model injection way or "View first" approach (PersonView.xaml.cs):
[Import]
public PersonViewModel ViewModel
{
set
{
this.DataContext = value;
}
}
I prefer using DataTemplates
It allows me to set multiple Views for the same ViewModel based on a property
My ViewModels are my application, and the View is nothing more than a pretty layer that makes my ViewModel's User-Friendly. If I use ViewModel injection, than the Views become my application and the development team suddenly has to worry about the UI side of things
My ViewModels are managed by other ViewModels. For example, one ViewModel might contain a collection of other ViewModels that get displayed in a TabControl. Adding or Closing tabs is done within the parent ViewModel. This sort of thing is not easily accomplished with the View controlling the application state.
I can initialize different ViewModels using parameterized constructors based on my needs instead of having to use generic Import ones
That's just a few reasons... I'm sure there's others but they don't come to mind right now
We use a view model first approach because we find it easier to manage, particular on larger scale enterprise apps. We use Caliburn.Micro to take care of view location and binding.
I use both. DataTemplates for small projects, but for larger or team projects we use view model injection.
Related
I have classes, A, B, C, D
A has a reference to E and B and to a list of C and D.
In AViewModel these are exposed in a tree.
The View for A looks like as in the picture.
When a node selected a correspondent view should be displayed.
There is ViewModels for E,B,C and D
My question is the following:
For example E is the selected node. I store it in AViewModel as "object SelectedItem".
What is the best way to create an EViewModel in a loosely coupled way, so that I do not want to reference EViewModel in AViewModel.
Update:
I was thinking about one solution, but I never seen that in other places:
For example I could expose only my POCOs (B, C, D, E) from AViewModel. And in XAML I could bind the ContentControl directly to these objects. With a converter I could have a BViewModel when I bind to B and so on.
A common and widely accepted way to communicate between view models and other components in a loosely coupled way in an MVVM application would be to use an event aggregator or a messenger. Please refer to the following links for more information.
Using the event aggregator pattern to communicate between view models: https://blog.magnusmontin.net/2014/02/28/using-the-event-aggregator-pattern-to-communicate-between-view-models/
MVVM - Messenger and View Services in MVVM: https://msdn.microsoft.com/en-us/magazine/jj694937.aspx.
Another option would be to use a shared service that you inject the view models with: https://social.msdn.microsoft.com/Forums/en-US/22907a0f-d805-4195-8272-7c284b72d2ee/example-of-using-shared-services-prism?forum=wpf
Using an event aggregator, messenger or shared service means that you can remove all references between the view model classes.
Instead of the view model classes having strong references to each other back and forth, each view model only knows about a single event aggregator/messenger/shared service and communicates only with this one. View model A may send any number of messages that any other view models may subscribe to listen to and handle internally.
My question is about best practices on topic of creating an instance of a ViewModel without having a tight coupling, not about the communication between loosely coupled ViewModels
Creating an instance of another view model without creating a string coupling is impossible. If one view model creates an instance of another view model they are by definition strongly coupled. To prevent this you could inject a view model with an interface type that the other view model implements, e.g.:
public ViewModelB(IViewModelA viewModelA)
{
//...
}
Then ViewModelB is dependant on an interface type instead of a concrete implementation of the ViewModelA. It's a bit better than doing something like this because then ViewModelA and ViewModelB will always be - as mentioned above - strongly coupled to each other:
public ViewModelB()
{
_viewModelA = new ViewModellA();
}
But if you really care about loose coupling between your view model classes, you should get rid of the direct references and start to use an event aggregator or a messenger to communcate between them.
If your A View displays the "list", plus the selected view, it's perfectly acceptable to have EViewModel reference in AViewModel. ViewModels may be the "reflection" of the views. So if the A view will contain an EView, AViewModel may contain an EViewModel. You just nest your view models so it creates the same tree as in the view layer.
On top of that, what I would do is not reference E or B,... in AViewModel, but reference only EViewModel, BViewModel,... So AView list does not display model classes but ViewModel classes. Your SelectedItem gets typed as a ViewModel and you can directly bind your "Display" view part to the SelectedItem. Then you can use the right DataTemplate on the view layer to display the according view. Hope it helps
I need to send notification from ViewModel to View in MVVM WPF application. In most cases it will be simple MessageBox on View side. Is it unacceptable violation of MVVM pattern to use types like System.Windows.MessageBoxResult or System.Windows.MessageBoxImage in ViewModel (in this case VM must reference UI-specific libraries)?
I need to pass title, message and notification type from VM and by creating custom enumerations I am in fact copying existing functionality from .NET Framework.
You don't need notification mechanism. That's one option. Another is using simple service class:
public class ViewModel
{
IDialogService _dialogService; //ctor injection or use service locator
public void CommandExecute()
{
_dialogService.ShowMessageBox(...);
}
}
public interface IDialogService
{
bool? ShowMessageBox(params....);
}
public class DialogService : IDialogService
{
public bool? ShowDialog(params...)
{
MessageBox.Show(params...);
}
}
I find this approach more straightforward, easier to understand and easier to debug. Messaging may easily turn into memory leak and in this case I don't see any benefit over my approach.
EDIT:
Will you use custom enum in ShowMessageBox parameters, or will you use
System.Windows.MessageBoxImage?
First of all, ViewModels belong to presentation layer. It is OK to use enums like System.Windows.MessageBoxImage in ViewModel.
In MVVM, ViewModels are separated from Views because of following reasons:
ViewModels expose data and logic from Model in such way that is easily consumable from Views (e.g DataBinding)
ViewModels are easier testable
ViewModels provides better design time support (Blendability, test data)
ViewModels separates application logic from the actual presentation markup which makes it easier to understand (readbility)
Does using enum like System.Windows.MessageBoxImage breaks any of the points above? The answer is no.
If you wanted to reuse IDialogService and your ViewModels on multiple platforms, for example WPF, UWP and Xamarin, then you need to create your own enum, because it may not exist on all platforms. The golden rule is: don't add another layer of abstraction if you don't need it.
You could have the view implement an interface, say INotificationService and then pass the view to the view model constructor. That won't violate MVVM, and you will still be able to bind the view model to the view using the DataContext property on the view.
I decided to keep ViewModel as clean of UI (View) stuff as possible, so I will create custom enumeration inspired by MessageBox and tailored exactly to my needs.
In a Windows 8 style app I have a View (or page) which is made up of several other Sub-Views.
Each of these has an associated ViewModel and they are defined and bounded via the MVVM Light ViewModelLocator
I then have a View2 which is made up of other Sub-Views which, again, are defined and bounded via the MVVM Light ViewModelLocator
What I want to do is to place instances of the View and View2 controls into a List on a MasterViewModel and then bind this list to a GridView on a MasterView file.
Each of the instances of View and View2 should render as they do if you were to create a single instance without placing it into a list.
What I have tried to do is create a List of Pages (as all views are instances of this type) and bind the GridView to this, but when I run the app the GridView appears empty.
I have seen an examples that use a DataTemplateSelector (http://www.wiredprairie.us/blog/index.php/archives/1705) and apply a DataTemplate to each of the items in the MasterView list.
I understand what this does, but what I don’t understand is how to create a DataTemplate for a View that is made up of other Views.
I’m sure I am overlooking something and / or just making this harder than it needs to be!
Thank you for any help :)
Normally in this case, you would be binding a list to a set of ViewModels, not views, and the data template selector (or ValueConverter depending on your flavour) would select and instantiate a view suited to the view model.
So if ViewA uses ViewModelA : ISubViewViewModel, and ViewB uses ViewModelB : ISubViewModel then your main ViewModel would contain a List<ISubViewModel> which has a set of ViewModelA & ViewModelB within it. The main view's ListBox is bound to the List<ISubViewModel> and the data template selector / ValueConverter resolves ViewA for ViewModelA's and ViewB for ViewModelB's.
Hope that makes sense, it's about as hard to describe the solution as it probably was to describe the problem. :)
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").
Can someone give me a quick summary of what a ViewModelLocator is, how it works, and what the pros/cons are for using it compared to DataTemplates?
I have tried finding info on Google but there seems to be many different implementations of it and no striaght list as to what it is and the pros/cons of using it.
Intro
In MVVM the usual practice is to have the Views find their ViewModels by resolving them from a dependency injection (DI) container. This happens automatically when the container is asked to provide (resolve) an instance of the View class. The container injects the ViewModel into the View by calling a constructor of the View which accepts a ViewModel parameter; this scheme is called inversion of control (IoC).
Benefits of DI
The main benefit here is that the container can be configured at run time with instructions on how to resolve the types that we request from it. This allows for greater testability by instructing it to resolve the types (Views and ViewModels) we use when our application actually runs, but instructing it differently when running the unit tests for the application. In the latter case the application will not even have a UI (it's not running; just the tests are) so the container will resolve mocks in place of the "normal" types used when the application runs.
Problems stemming from DI
So far we have seen that the DI approach allows easy testability for the application by adding an abstraction layer over the creation of application components. There is one problem with this approach: it doesn't play well with visual designers such as Microsoft Expression Blend.
The problem is that in both normal application runs and unit test runs, someone has to set up the container with instructions on what types to resolve; additionally, someone has to ask the container to resolve the Views so that the ViewModels can be injected into them.
However, in design time there is no code of ours running. The designer attempts to use reflection to create instances of our Views, which means that:
If the View constructor requires a ViewModel instance the designer won't be able to instantiate the View at all -- it will error out in some controlled manner
If the View has a parameterless constructor the View will be instantiated, but its DataContext will be null so we 'll get an "empty" view in the designer -- which is not very useful
Enter ViewModelLocator
The ViewModelLocator is an additional abstraction used like this:
The View itself instantiates a ViewModelLocator as part of its resources and databinds its DataContext to the ViewModel property of the locator
The locator somehow detects if we are in design mode
If not in design mode, the locator returns a ViewModel that it resolves from the DI container, as explained above
If in design mode, the locator returns a fixed "dummy" ViewModel using its own logic (remember: there is no container in design time!); this ViewModel typically comes prepopulated with dummy data
Of course this means that the View must have a parameterless constructor to begin with (otherwise the designer won't be able to instantiate it).
Summary
ViewModelLocator is an idiom that lets you keep the benefits of DI in your MVVM application while also allowing your code to play well with visual designers. This is sometimes called the "blendability" of your application (referring to Expression Blend).
After digesting the above, see a practical example here.
Finally, using data templates is not an alternative to using ViewModelLocator, but an alternative to using explicit View/ViewModel pairs for parts of your UI. Often you may find that there's no need to define a View for a ViewModel because you can use a data template instead.
An example implementation of #Jon's answer
I have a view model locator class. Each property is going to be an instance of the view model that I'm going to allocate on my view. I can check if the code is running in design mode or not using DesignerProperties.GetIsInDesignMode. This allows me to use a mock model during designing time and the real object when I'm running the application.
public class ViewModelLocator
{
private DependencyObject dummy = new DependencyObject();
public IMainViewModel MainViewModel
{
get
{
if (IsInDesignMode())
{
return new MockMainViewModel();
}
return MyIoC.Container.GetExportedValue<IMainViewModel>();
}
}
// returns true if editing .xaml file in VS for example
private bool IsInDesignMode()
{
return DesignerProperties.GetIsInDesignMode(dummy);
}
}
And to use it I can add my locator to App.xaml resources:
xmlns:core="clr-namespace:MyViewModelLocatorNamespace"
<Application.Resources>
<core:ViewModelLocator x:Key="ViewModelLocator" />
</Application.Resources>
And then to wire up your view (ex: MainView.xaml) to your viewmodel:
<Window ...
DataContext="{Binding Path=MainViewModel, Source={StaticResource ViewModelLocator}}">
I don't understand why the other answers of this question wrap around the Designer.
The purpose of the View Model Locator is to allow your View to instantiate this (yes, View Model Locator = View First):
public void MyWindowViewModel(IService someService)
{
}
instead of just this:
public void MyWindowViewModel()
{
}
by declaring this:
DataContext="{Binding MainWindowModel, Source={StaticResource ViewModelLocator}}"
Where ViewModelLocator is class, which references a IoC and that's how it solves the MainWindowModel property it exposes.
It has nothing to do with providing Mock view models to your view. If you want that, just do
d:DataContext="{d:DesignInstance MockViewModels:MockMainWindowModel, IsDesignTimeCreatable=True}"
The View Model Locator is a wrapper around some (any) Inversion of Control container, such as Unity for example.
Refer to:
How to handle dependency injection in a WPF/MVVM application
http://blog.qmatteoq.com/the-mvvm-pattern-dependency-injection/