MVVM Correct using of the pattern - c#

I just want to know if i'm doing it right. I have a mainview (MainView) with it's viewmodel (MainWindowViewModel). In the MainView there is a button to call another view (SubView). The SubView hast also a ViewModel (SubViewModel). After the SubView is closed through it's viewmodel i want to access a property in the subviewmodel from the mainviewmodel.
The code to call the subview from the mainviewmodel and access the property looks like:
private void SubViewExecute(object parameter)
{
SubView sub = new SubView();
bool? result = sub .ShowDialog();
if (!result.HasValue || !result.Value) return;
if (sub.DataContext is SubViewModel)
{
SubViewModel subViewModel = (sub.DataContext as SubViewModel);
string property = subViewModel.Property;
}
}
Am I doing the mvvm-pattern correct, or is there a better way to achieve want i want?

To your core question: "Am I doing the mvvm-pattern correct, or is there a better way to achieve want i want?"
No, you aren't adherring to the core principle of MVVM correctly, and there is a better way to achieve what you want (if I understand what you want correctly).
First, MVVM comes from a need to make all layers testable without requiring knowledge of the layer "above." For instance, your application should be able to technically do everything it's supposed to through just the Model; it should be ableo to retrieve, update, and create data as needed - even if this data is not presented in a user intuitive manner, yet.
Second, your applicaiton should then be able to technically do everything that the User would want it to do through the View-Model, but without any kind of UI. So you should be able to "look" at your data and perform the various program functions, like Saving.
Then, when you throw your view on top, all you need is data-binding and event handling, and you are good to go! (mostly)...
Mainly, it is the View's responsibility to correctly manage it's own DataContext from the ViewModel; it is not the ViewModel's job to push a datacontext onto a particular View. Another way to look at it is, the View accesses methods and properties in the ViewModel to cary out the work requested by the user in the user interface.
So, I would start by flipping your code around, so that the View controls which views are active at any given time, and that each view is ware of it's own data context, and methods to utilize them.
(Now, before the SO community jumps on me about not saying anything about the VM first approach - here it is. You could try a VM first approach, but it is more difficult to understand at first, and you are going to want to use a framework to help you, like Caliburn.Micro or MVVMLite or something)
So, for View First, what you want to do is have the MainView know how to populate itself with SubViews. It's the job of the MainView to ensure that it's data context is the correct MainViewModel, as each SubView is created in the MainView, the MainView will ensure that each SubView has the correct SubViewModel instance set as it's data context.
This should be logically easy to approach because your MainViewModel already contains a set of SubViewModels (of various kinds) inside.
Hope that helps get you going, if you have more specific code questions (with sample code) we can help you futher.

It's not entirely clear what you want here - but this is definitely violating MVVM in a purist sense.
Your MainViewModel, in this example, needs direct knowledge of the View layer (SubView), which is typically avoided whenever possible.
However, the best approach to avoid this depends a lot on whether you're using a framework (many frameworks have tooling for matching a View to a ViewModel, and displaying dialogs, etc), which framework, and whether you're working View-first or ViewModel-first.

Related

How to instantiate an object in ViewModel and edit that in another ViewModel or user control

I'm new to c# and mvvm.
I have a class that has many properties, and because of that, it is not possible to present every property to user in one page. Therefore, I decided to break the UI into 4 different part. I designed one user control for each of these parts.
As of now, I have 4 different user controls which are presented to user with the help of a side bar selection.
However, I still have one object to work with and it is not possible to break the object too.
The problem is I cant access to object from user controls' code behind. It means that I can bind object with UI but I'm not able to change parameters in code behind.
Welcome to SO!
On one hand you talk about MVVM and data-binding, but then on the other hand you talk about modifying changing parameters in code-behind. These are antithetical design patterns. Pick one!
If you are implementing MVVM then, as you know you have the View (UI e.g. Page1.xaml) in XAML, with code behind (Page1.xaml.cs) these then use a ViewModel (e.g. Page1ViewModel.cs) as their data context, i.e. where they can access the Model.
You do not have to have a one-to-one correlation of Views, ViewModels and Models.
You can have more than one View use the same ViewModel as its data context and you can have a ViewModel contain yet more ViewModels and a ViewModel can reference several Models if required.
So in your situation I'd have several pages reference the same ViewModel.

MVVM correct flow of events

I'm somewhat new to MVVM but I have had my hands on it for some time now. Unfortunately, perusing the internet there seems to be no solid consensus on the best way for an application to process events in MVVM. I have a situation pictured below in which I am combining two controls - each in a self contained xml that i'm going to call two separate views: ListBox and ButtonPanel.
How should the direction of events flow then? Let's take a scenario where upon clicking my button in the button panel, a file is created in the list box control. Would the flow of events in image one or in image two be more appropriate?
Event Flow One - Communicating ViewModel to ViewModel:
Event Flow Two - All Front end classes don't communicate. All messages are passed via the Application Layer (whatever is hooked up to the back end: db, processing functions, etc..)
Please note - i didn't picture it but I am using ICommand to pass the click event from my Button Panel View to my Button Panel View Model.
And lastly once again my question is: How should events be processed in an MVVM flow. Are either of my graphics appropriate?
* **EDIT IN RESPONSE TO Ed Plunkett's ANSWER ***
Is this then the sort of event flow you would expect:
Is this closer to the correct architecture?
In this image the << >> between ViewModels are actually properties being exposed to the views, and the majority of the events are being handled as bindings there in the view.
My concerns with this are:
The Master ViewModel is now responsible for collecting information from both views. I'm not sure how to handle this without using mediator/messenger - that is without tightly coupling my parent view model to the child. Either i'd have to register events by name in all view models, or make specific callbacks by name for each of the viewmodels, so a mediator would still be necessary to achieve loosely coupled design (which is the entire advantage of using MVVM).
Even if i'm wrong in point 1 - what is the advantage of using a parent child ViewModel relationship?
Concerning the point of ViewModels don't know what a button or a panel is:
I agree. You can ignore my naming of classes here. I've just done it this way to make the question easy to understand - named classes so that an onlooker knows what control is being handled in each. My actual classes are named based on the data they handle, not the component.
Simplest case: One viewmodel.
The button invokes a command that it gets from a property of the viewmodel.
The viewmodel also has a property something like
public ObservableCollection<SomeFileViewModelClass> Files { /* INPC stuff */ }
The button has no idea what the command does. Presumably the command tells the viewmodel to create a file, and add a new instance of SomeFileViewModelClass to Files.
Meanwhile, back in the XAML, the ListBox is using Files as an items source:
<ListBox
ItemsSource="{Binding Files}"
...
...so the listbox will automatically update to show the new file.
If you want your button panel to have its own viewmodel (you almost certainly don't, and even if you do, don't call it a "button panel viewmodel"; viewmodels don't know what buttons or panels even are) and your file list to have its own viewmodel (maybe), make those kind of things child viewmodels of the main viewmodel. The main viewmodel creates them and manages relationships between them.
public FilesViewModel FileList { /* INPC stuff */ }
Maybe FileList now owns ObservableCollection<SomeFileViewModelClass> Files -- but if that's all it owns, it isn't a viewmodel. Just put that Files property on the main viewmodel.
<Button Content="Create File" Command="{Binding CreateFileCommand}" />
<!-- ... snip -->
<ListBox ItemsSource="{Binding FileList.Files}" />
Maybe CreateFileCommand should be a property of FilesViewModel, if that even exists.
Keep it as simple as possible, but no simpler.
Do not design a UI and then create one viewmodel for each thing in the UI. That's backwards. Controls don't have viewmodels.
Design viewmodels to model the things your application needs to deal with. Parent and child viewmodels, based on the actual relationships between the actual stuff (personally, I prefer to model the smallest "leaf node" things first, then work my way into the center). Then add views to display them to the user. This takes a little getting used to, but it pays off.
Your viewmodels are "The Program". You write views to display the program to the user and let the user talk to the program. You write models/database/file access/whatever to let the program store and retrieve state.
Your "All messages are passed via the Application Layer" idea is not MVVM.
Your second thing with the yellow "mediator/messenger" box is close to correct, but there's no "mediator/messenger"; parents talk to children. If a child will need to know something about a sibling, you would manage that by having the children expose events. The parent can wire up event handlers among the children -- to do it quick and dirty, you can always handle INotifyPropertyChanged.PropertyChanged on a child, but specialized events are often preferred. Dependency injection is another option but it's easy to end up writing classes with a maze of dependencies. DI can turn into an antipattern, and multi-colored block diagrams of the information flow in user interfaces is a leading indicator that it's about to.
Your case is simplified, but you'd really have a "ListBox View" that contains a ListBox and a "Button View" that contains the button. Both of those views would be child views of the "Main Window View".
I'd have to disagree with Ed here and say I would never combine VMs... that breaks the single responsibility paradigm that MVVM tries to install.
The standard MVVM way of having VMs communicate is through the messenger / event aggregator paradigm.
So i'd vote for workflow #1. ALMOST...
VM's should NOT send a message to another VM to write to a DB, etc. That's what models are for.
If you want to abstract away the DB, the standard way to do that is to define a IDataProvider type interface and use DI to inject it into VMs that need it. You'll find as your app gets larger and more complicated, DI and MVVM are a match made in heaven.
MVVM + DI + Messenger all work together beautfully and keep everything seperate and organized.
Personally I like to keep V <-> VMs 1:1 with no code behind, but that's the super purist definition of MVVM.
EDIT: Just to clarify, I don't think you really mean you are just plopping 2 controls on a form and making each a VM, I wouldn't do that. Break the UI into logical "regions" and each "region" would have a VM and a V.

How can control in the view get specific data from view model?

I have multiple of views (user controls), each with its own ViewModel. To navigate between them I am using buttons. Buttons display image and text from corresponding view model and also need column and row (because there are like 10 views: 10 columns with different number of rows each).
Right now buttons are created dynamically (I made a Navigator control for this) and for view models I have base class to hold text, image, column and row. Number of views available will be different (depends on user level and certain settings), that's why it's I need control here.
Question: how shall my control get data from view models?
Right now I have interface INavigator, defined in (lol) control itself. And view models implement it. I could go opposite, let my control to know about view models. Both looks wrong.
There is a single Navigator control what has, lets say, Items bound to a list of view models. It can cast each view model to INavigator or ViewModelBase (common for all pages) to obtain specific view model image, text, column and row. So either view model knows about control (to implement INavigator) or control knows about ViewModelBase.. And this is a problem, both solution bind tight control and view models, which is bad in mvvm.
Schematically
The way you've drawn your diagram answers your own question as to how you should structure the code for this.
What you need is one VM (let's call it MainVM) which contains an ObservableCollection<VMBase> of the other VMs (using your base type so that they can all happily live in the same collection).
Your View needs an ItemsControl (bound to your ObservableCollection<VMBase>) where you specify a DataTemplate for the Button using the properties exposed by the VMBase type only. Set the Command property in the Button to call SwitchCommand, CommandParameter is set to the item itself (i.e. {Binding .}).
Your View also needs a ContentControl bound to a SelectedVM property on MainVM which you can populate.
Implement SwitchCommand to set the SelectedVM property based on the value from the CommandParameter.
public void ExecuteSwitchCommand(object parameter)
{
var vmBase = parameter as VMBase;
if (vmBase != null)
SelectedVM = vmBase;
}
All properties mentioned here should be INotifyPropertyChanged enabled so that the View registers when they change and updates the UI.
To get the different UIs for the ContentControl, add type-specific DataTemplates for each of your specific VM types to the Resources file of your View (or if you're smart and are building a custom plug-in framework, merge the Resource Dictionaries).
A lot of people forget with MVVM that the whole point is that there is a purposeful separation of View from ViewModel, thus meaning you can potentially have many Views for a single ViewModel, which is what this demonstrates.
I find it's easiest to think of MVVM as a top-down approach... View knows about it's ViewModel, ViewModel knows about its Model, but Model does not know about its ViewModel and ViewModel does not know about its View.
I also find a View-first approach to development the easiest to work with, as UI development in XAML is static (has to be).
I think a lot of people get to wrapped up in 'making every component (M, V, VM) standalone and replaceable', myself included, but I've slowly come to the conclusion that is just counter-productive.
Technically, sure you could get very complicated and using IoC containers, create some ViewLocator object which binds a View-type to a ViewModel-type, but... what exactly does that gain you besides more confusion? It makes it honestly harder (because I've done this at one point) to develop because now you've lost design-time support first and foremost, among other things; and you're still either binding to a specific view model interface in your view or creating the binding at run-time. Why complicate it?
This article is a good read, and the first Note: explicitly talks about View vs. ViewModel. Hopefully, it will help you draw your own conclusions.
To directly answer your question, I think having your ViewModels implement an INavigator interface of some sort is probably ideal. Remember your VM is 'glue' between your view and model/business logic, its job is to transform business data into data that is consumable by your views, so it exists somewhere between both your UI and business layers.
This is why there are things like Messengers and View Services, which is where your navigator service on the ViewModels can fit in nicely.
I think the design has led to a no way out situation.
I believe that creating a custom button control where the dependency properties tie the image, the row and column actually provide a way for the page, which it resides on ,to get that information to them; whether they are dynamically created or not.
Continuing on with that thought. There is no MVVM logic applied to a custom control, the control contains what it needs to do its job and that is through the dependency properties as mentioned. Any functionality of the button should be done by commanding; all this makes the button data driven and robust enough to use in a MVVM methodology or not.
Question: how shall my control get data from view models?
There should only one viewmodel which is the page the control resides on. The control is simply bound to information which ultimately resides on that VM. How it gets there, that is up to the programmer. If the button is going to contain state data, that is bound from its dependency property in a two way fashion back to the item it is bound to.
By keeping VMs out of the buttons and only having one VM that is the best way to segregate and maintain the data. Unless I am really missing something here....
Same as others here I find it a bit hard to actually understand what you are asking, so this is quite general. The answer to the question header is simply: the Control gets the data from the ViewModel through bindings, always. You set the DataContext of your Control to the corresponding ViewModel, and from there you keep the ViewModel and the Control synchronized:
If you add an ItemsControl containing buttons to the View, you add an ObservableCollection<ButtonViewModel> to the ViewModel and bind the ItemsSource of the ItemsControl to this.
If you allow the user to dynamically add content to the View, the actual code that does it resides in the ViewModel, e.g. when the user clicks on a button "Add Button", you use the Command property to call a ViewModel method that adds a ButtonViewModel to the collection and the View will automatically reflect your changes.
There do exist complicated cases that are impossible to code exclusively in the ViewModel, I have found Behaviors to be the missing link there, but I'll get into that when you show me the specific case.
If you'd like to get a working example, please provide as much code as you can, with your exact expectations of what it should do.

Should I always use Command even though it might not be necessary?

Should I always use Command even though it might not be necessary?
Or should I only use Command in the case where more things, menu items, buttons,
whatever, when clicked execute the same code?
Maybe it is good practice to always use Command, or maybe it adds additional
unnecessary complexity. I am new to WPF so please share some advices.
If you're using the MVVM pattern, which is mandatory in every serious WPF application, 'ICommand' is the way to go for every action that is not purely interface logic.
I'll explain:
As you probably know, the MVVM pattern distinguishes between Model, ViewModel and View, where the ViewModel mediates between Model and View. The ViewModel usually holds all the data which is consumed by the view and which you bind your view to. The important thing is:
The View is agnostic of the ViewModel
This means, although your View is bound to the ViewModel, it doesn't reference it, there is no logical dependency to the ViewModel. The 'ICommand' bridges this gap: It kind of packs an action into a bindable property. That's the main point, probably:
A command wraps up an action or function into a WPF databindable
property
And as databinding is the mechanism which, in MVVM, View and ViewModel are connected with each other, the command is the vehicle to perform every action, no matter if it is triggered by one control or by many, that transcends the sphere of pure UI (which is almost everything):
Have a look here (MSDN), where this image is taken from:
If you don't use MVVM I'm not sure whether you need commands at all. There is no significant difference to WinForms then, regarding the UI event handling. But again: MVVM and WPF go hand in hand, in my opinion.

MVVM - what is the ideal way for usercontrols to talk to each other

I have a a user control which contains several other user controls. I am using MVVM. Each user control has a corresponding VM. How do these user controls send information to each other? I want to avoid writing any code in the xaml code behind. Particularly I am interested in how the controls (inside the main user control) will talk to each other and how will they talk to the container user control.
EDIT:
I know that using events-delegates will help me solve this issue. But, I want to avoid writing any code in xaml code-behind.
Typically, it's best to try to reduce the amount of communication between parts, as each time two user controls "talk" to each other, you're introducing a dependency between them.
That being said, there are a couple of things to consider:
UserControls can always "talk" to their containing control via exposing properties and using DataBinding. This is very nice, since it preserves the MVVM style in all aspects.
The containing control can use properties to "link" two properties on two user controls together, again, preserving clean boundaries
If you do need to have more explicit communication, there are two main approachs.
Implement a service common to both elements, and use Dependency Injection to provide the implementation at runtime. This lets the controls talk to the service, which can in turn, keep the controls synchronized, but also keeps the dependency to a minimum.
Use some form of messaging to pass messages between controls. Many MVVM frameworks take this approach, as it decouples sending the message from receiving the message, again, keeping the dependencies to a minimum.
Your conceptual problem is here:
Each user control has a corresponding VM.
Having a separate ViewModel for every view pretty much defeats the concept of a ViewModel. ViewModels should not be one-to-one with views, otherwise they are nothing but glorified code-behind.
A ViewModel captures the concept of "current user interface state" -- such as what page you are on and whether or not you are editing -- as opposed to "current data values'.
To really reap the benefits of M-V-VM, determine the number of ViewModel classes used based on distinct items that need state. For example, if you have a list of items each of which can be displayed in 3 states, you need one VM per item. Contrarily, if you have three views all of which display data in 3 different ways depending on a common setting, the common setting should be captured in a single VM.
Once you have strucutred your ViewModels to reflect the requirements of the task at hand you generally find there is no need nor desire to communicate state between views. If there is such a need, the best thing to do is to re-evaluate your ViewModel design to see if a shared ViewModel could benefit from a small amount of additional state information.
There will be times when the complexity of the application dictates the use of several ViewModels for the same model object. In this case the ViewModels can keep references to a common state object.
There are many differenct mechanisms for this, but you should first find out in what layer of your architecture this communication belongs.
One of the purposes of the MVVM framework is that different views can be made over the same viewmodel. Would those usercontrols talk to each other only in the view you are currently implementing, or would they have to talk to each other in other possible views? In the latter case, you want to implement it below the view level, either in the viewmodel or the model itself.
An example of the first case may be if your application is running on a very small display surface. Maybe your user controls have to compete for visual space. If the user clicks one usercontrol to maximize, the others must minimize. This would have nothing to do with the viewmodel, it's just an adaption to the technology.
Or maybe you have different viewmodels with different usercontrols, where things can happen without changing the model. An example of this could be navigation. You have a list of something, and a details pane with fields and command buttons that are connected to the selected item in the list. You may want to unit test the logic of which buttons are enabled for which items. The model isn't concerned with which item you're looking at, only when button commands are pressed, or fields are changed.
The need for this communication may even be in the model itself. Maybe you have denormalized data that are updated because other data are changed. Then the various viewmodels that are in action must change because of ripples of changes in the model.
So, to sum up: "It depends...."
I think the best solution would be using Publisher/Subscriber pattern. Each control registers some events and attaches delegetes to events exposed by other controls.
In order to expose events and attach to them you would need to use some kind of Mediator/EventBroker service. I found a good example here
The best way to do this in my opinion is via Commanding (Routed Commands / RelayCommand, etc).
I want to avoid writing any code in the xaml code behind.
While this is a laudable goal, you have to apply a bit of practicality to this, it shouldn't be applied 100% as a "thou shalt not" type of rule.
You can communicate between elements on the UI by using element binding, so assuming a user control you created exposes a property, the other user controls could bind to it. You can configure the binding, use dependency properties instead of basic properties / implement INotifyPropertyChanged but it is in theory possible, but does require some forethought to enable to communication this way.
You will probably find it far easier using a combination of events, code and properties than try a pure declarative way, but in theory possible.
You can share some View Model objects between controls as well as Commands...
For example, you have some main control, which contains two other controls. And you have some filtering functionality in the main control, but you want to allow user to set some part of the filter in the first sub-control (like "Full filter") and some part of the filter in another (like "Quick filter"). Also you want to be able to start filtering from any of sub-controls. Then you could use code like this:
public class MainControlViewModel : ObservableObject
{
public FirstControlViewModel firstControlViewModel;
public SecondControlViewModel firstControlViewModel;
public ICommand FilterCommand;
public FilterSettings FilterSettings;
public MainControlViewModel()
{
//...
this.firstControlViewModel = new FirstControlViewModel(this.FilterSettings, this.FilterCommand);
this.secondControlViewModel = new SecondControlViewModel(this.FilterSettings, this.FilterCommand);
}
}
public class FirstControlViewModel : ObservableObject
{
//...
}
public class SecondControlViewModel : ObservableObject
{
//...
}
In the main control XAML you will bind sub-controls DataContext to the appropriate View Models. Whenever a sub-control changes filter setting or executes a command other sub-control will be notified.
As others have said you have a couple of options.
Exposing DepedencyProperties on your user controls and binding to those properties provides a pure XAML solution in most cases but can introduce some UI dependencies in order for the bindings to see each other
The other option is a decoupled messaging pattern to send messages between ViewModels. I would have your user controls bind to properties on thier own VM's and then on the property change inside that VM it can "publish" a message that notifies other "subscribers" that something has happened and they can react to that message however they want to.
I have a blog post on this very topic if it helps: http://www.bradcunningham.net/2009/11/decoupled-viewmodel-messaging-part-1.html
If you're using strict MVVM, then the user-control is a View and should only "talk", or rather, bind, to its ViewModel. Since your ViewModels most likely already implement INotifyPropertyChanged, as long as they have a reference to each other, they can use the PropertyChanged events to be notified when properties change, or they can call methods (better if it's through an interface) to communicate with each other.

Categories