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
Related
This is the link i am following for learning MVVM in WPF and i have a question:-
https://www.tutorialspoint.com/mvvm/mvvm_first_application.htm
DataContext of the WPF window is set to a VIEWMODEL object.
Itemsource of a List-DataTemplate is set to a List from the same VIEWMODEL Object.
The Model contains an implementation of INotifyPropertyChanged.
When i update the view,the INotifyPropertyChanged of MODEL gets fired ie VIEW is directly updating the MODEL while what i have understood till now is that VIEW interacts with the VIEWMODEL only via Bindings and Commands and never with the MODEL DIRECTLY.It is always the ViewModel which interacts with the Model to fetch data for the View.But here,the View is updating the Model DIRECTLY.This is confusing me owing to my limited knowledge.
Please guide.
If the view model exposes the model through a property, the view may actually bind directly to the model through this property. This doesn't really violate the MVVM pattern and is perfectly fine, especially if the model class implements the INotifyPropertyChanged interface. If it does, you can say that the model is kind of a (child) view model.
A "real" model such as a domain object or a service shouldn't have any knowledge about WPF and how you raise change notifications to a view. Therefore it rarely makes sense to bind directly to such objects but if your models are "WPF aware" and implements view related interfaces, you can bind to them without any issues.
It is a common error to bind the Model thru lists to the View. The correct approach would be always to create a ViewModel of that Model (the list element) and bind to it.
For example:
Otherwise you are opening the door to including data on ModelB that should be stored in the ViewModelB.
I think this is a rather basic question, but I haven't been able to find an answer to this.
I have the following scenario:
Without using any form of EntityFrameWork I have a PersonViewModel and a PersonDetailsViewModel, which inherits from the PersonViewModel. In my PersonView I display a collection of PersonViewModels in a grid. I have properties like Name, DateOfBirth etc, as columns. When I double click on a person a PersonDetailView pops up which is bound to a PersonDetailsViewModel. In this View there is extra information shown about the person (Gender, SocialSecurity number etc.). The user I allowed to edit all properties.
Now I wonder what the best/common approach is to make sure that the PersonViewModel gets updated with the values that have been editted in the PersonDetailsViewModel.
I can think of several options. For starters I could opt for not using different ViewModels, but instead use PersonDetailViewModels to show in the grid, but the downside to that is that I would need to retrieve a lot of unnecessary data per ViewModel.
I can also synchronise the corresponding properties after the PersonDetailsView closes.
The third option I can think of is that instead of inheriting from the PersonView I will include a property in PersonDetailsView that is of the type PersonView and expose it's properties and use it for binding in the PersonDetailsView. All other extra properties in PersonDetailsViewModel will then be retrieved in it's constructor.
In my experience, the best way to update view models who share the same data is to use the Mediator pattern to send a notification message that the data has updated.
In order to have a good object oriented design we have to create lots
of classes interacting one with each other. If certain principles are
not applied the final framework will end in a total mess where each
object relies on many other objects in order to run. In order to avoid
tight coupled frameworks, we need a mechanism to facilitate the
interaction between objects in a manner in that objects are not aware
of the existence of other objects.
Source http://www.oodesign.com/mediator-pattern.html
It is syntactically important to your design that the notification says what has happened (the data was updated) and not what should happen (data gets reloaded) because that response may not stay the same as the system evolves.
Often, common MVVM libraries have Mediator implementations in them. For example, Prism's EventAggregator.
in Addition to Sheridans answer. i would expose the Detail as a property of type PersonDetailsViewModel
public class PersonViewModel
{
public PersonDetailsViewModel Detail {get;set;}
}
then your xaml looks simply like that
<TextBlock Text="{Binding Detail.Gender}"/>
EDIT1: in addition to the comments above
i would not do any inheritence (thats what user1087702 wrote in his question). i would simply create 2 classes: PersonVM and PersonVMDetail. And if the request is, to show Details from my person object, why in hell shouldn't i just create a public Property in my PersonVM class of type PersonVMDetail - to fullfill this request?
The simplest way to achieve your requirements would be to add a constructor to your PersonViewModel class that takes a PersonDetailsViewModel instance and updates its common properties:
public PersonViewModel(PersonDetailsViewModel personDetailsViewModel)
{
Name = personDetailsViewModel.Name;
...
DateOfBirth = personDetailsViewModel.DateOfBirth;
}
...
PersonViewModel = new PersonViewModel(PersonDetailsViewModel);
Of course, this doesn't have to be in the constructor... it could just as easily be a method in the PersonViewModel class, or even a helper method in a separate Factory Pattern class, it's up to you.
I'm having trouble understanding how to apply the MVVM pattern when Lists/Collections are involved.
Say the MainModel has a few properties and methods, as well as a list that contains other DetailModel objects. The DetailModel objects can be added, removed, or re-ordered.
The MainView will show a few controls related the the root model, and have a ListBox populated from the list. Each item will have it's own sub-view via a DetailModelView UserControl.
Finally, there is a MainViewModel. This has properties backed by the MainModel's properties and methods, bound to the Main View, with change notification keeping everything in sync. (Up to this point, I am comfortable with the pattern - more stating this in case there is something fundamental I am missing...)
When it comes to handling the list, I get confused. I have come across several examples where the MainViewModel simply exposes the list of DetailModels to the view, and the DetailModelViews are bound directly to the models. This functions, but is problematic. It does not consistently following the pattern (no DetailViewModel exists), and it drives me to include some UI-related code in my detail models. It seems clear to me that the MainViewModel should expose a list of DetailViewModels for the UI to bind, but I am stuck on how to implement such a thing!
How should manage the two lists (DetailModels and DetailViewModels)? I am really confused as where I initially populate the DetailViewModel list, and how I should handle adding, removing, or changing the order of the items to keep them synchronized!
Usually Models are nothing more than data objects. They shouldn't contain any code to do things like add/remove items from a list. This is the ViewModel's job.
In your case, I would create a MainViewModel that has the following properties:
ObservableCollection<DetailViewModel> Details
ICommand AddDetailCommand
ICommand RemoveDetailCommand
If your MainModel class is a data object, you can either expose it, or it's properties from the MainViewModel as well. Exposing it's Properties is the "MVVM purist" approach, while exposing the entire Model is sometimes more practical.
Your MainViewModel is in charge of creating the initial list of DetailViewModels, and it is in charge of Adding/Removing these items as well. For example, in the PropertyChanged event for the MainViewModel.MainModel property, it might rebuild the MainViewModel.Details collection, and the CollectionChanged event for the MainViewModel.Details property would update MainViewModel.MainModel.Details
You are right to have a separate DetailModels list and DetailViewModels list. The DetailViewModels list should be a property of type ObservableCollection<DetailViewModel>. You can populate the observable list when you set the Model (or at construction time, if you pass the model into the constructor of your ViewModel.)
private ObservableCollection<DetailViewModel> m_details;
public IEnumerable<DetailViewModel> Details
{
get { return m_details; }
}
You can the subscribe to m_details.CollectionChanged. This is where you can handle re-ordering the contents of the list in the Model.
I hope this helps.
In my experience, the only time you get away with exposing model objects to the view is if you're doing simple read-only presentation, e.g. displaying a string property in a ComboBox. If there's any kind of actual UI involving the object (especially one involving two-way data binding), a view model is needed.
Typically, a master VM's constructor will look like this:
public MasterViewModel(MasterModel m)
{
_Model = m;
_Detail = new ObservableCollection<DetailViewModel>(m.Detail);
}
where MasterModel.Detail is a collection of DetailModel objects, and _Detail is a backing field for a Detail property that's exposed to the view.
As far as adding, removing, and reordering items in this list is concerned, in the UI at least this will be done through commands on the MasterViewModel, which must manipulate both MasterModel.Detail and MasterViewModel.Detail. That's a bit of a pain, but unless you want to repopulate MasterViewModel.Detail after every change to MasterModel.Detail, it's really unavoidable.
On the other hand, if you've been wondering "why would I ever need to write unit tests for view models?", now you know.
Here is an answer that I think addresses this issue very nicely using an ObservableViewModelCollection<TViewModel, TModel>
It's nice and lazy. It takes an ObservableCollection and a ViewModelFactory in the ctor. I like it because it keeps state at the model layer where it belongs. User operations on the GUI can invoke commands at the VM which manipulate the M via public methods on the M. Any resulting changes at the M layer will be automatically handled by the class in this link.
https://stackoverflow.com/q/2177659/456490
Note my comment regarding SL vs. WPF
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.
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").