First off, I'm new to MVVM, so please help me out on this :)
Suppose I have multiple views in my app. In my case, I have an editor view, and a browser view.
Both of them have to work with a viewmodel of a "node" I'm editing.
So where does the viewmodel actually get created ?
Suppose the Editor is told to edit a certain node - It could create a new "NodeViewModel" and work with that. But at the same time, there's a NodeBrowserView, which allows people to shortcut-select a different node.
Basicly - I need the EditorView to work with the same ViewModel as the BrowserView, so I need a generic "GetViewModelfor(X)" method.
So how is this supposed to work ? :)
Cheers :)
Both your editor view and browser view should operate on some kind of NodeViewModel. You shouldn't need separate view models just for the different view scenario.
Now, can you edit not-yet-shown-to-user node? If no (as in, user decides what is edited), view models should be created at the very first time their content needs to be presented to user. In most cases this would in some browser/details views, so that user can select element and then chose to edit it.
Edit:
Regarding your comment. NodeViewModel should be provided for editor view.
The providing part can be done for example via constructor injection or by setting view's data context manually. For example, when user browses all nodes in the browser view, he can double click on the list item and editor view will pop-up:
// this will probably be done in response to event
private void ListItemDoubleClick(object sender, EventArgs e)
{
NodeViewModel currentItem = // extract current list item
EditorView editorView = new EditorView(currentItem);
editorView.Show();
}
Alternatively, if you want to avoid this kind of strong coupling between CompositeView and EditorView you can always use events, however it's not always necessary.
One more thing I was thinking of in terms of design would be adding extra view model, call it NodesListViewModel. How the program flow might look like:
At application startup, get your nodes (be it from DB, file, service, anything)
Create instance of NodeListViewModel which takes dependency on IList<Node> (list of node entities)
NodeListViewModel will build and expose collection of NodeViewModel elements
Create instance of your main program window, which uses composite view. It needs NodeListViewModel as its data context.
Whenever user decides he needs to edit item, it's all ready. Browser has a list of all NodeViewModels, it can easily pick up current and pass it to dedicated view.
In cases like this I prefer to use a single main view model and have a "current item" that the view connects to instead. This is a lot easier to do instead of passing / creating new view models around each time a user clicks a different node / grid row / etc. I really see no need to a separate view model either when the same operations can be achieved in the overall view model. It reduces complexity and reduces the change of creating objects (view models) and leaving them hanging around because a reference to them was not released until the application is closed.
Related
I have a WPF application that I want to present a list of non-homogeneous VIEWS. I want to have a button that I can write a handler for that would display a view. Then since it is a view the user could interact with it (enter values in a TextBox for example) using an underlying view model (MVVM). So let me explain further. The flow that I am looking to achieve is that a user selects which view to display. The view is displayed in a list. Then the user interacts with this instance of the view. When the user clicks on the button again a possibly different view is displayed and the user can now interact with two views. This continues as long as the 'add' button is clicked adding to the views in the list. This is further complicated because first, each of these views first are different. The particular view that should be displayed is dependent on a parameter that is passed to the command. Second it is complicated because each of these views also have dependencies that are passed in via IoC and on down to the associated view model. In other words there is not a parameterless constructor for the view models. So I cannot define a view model/view relationship like:
<Window.Resources>
<DataTemplate DataType="{x:Type views:SelectCustomerViewModel}"\>
<views:SelectCustomerView/>
</DataTemplate>
</Window.Resources>
I have searched and I see that one solution that comes close using the ItemTemplateSelector as outlined here. But as far as I can tell this only is a solution for a non-homogeneous display. If I revert to a list of views then it seems like I am breaking the MVVM model, as I would have to construct an appropriate view and assign the appropriate view model. How should I display/bring up a dynamic list of different views using the IoC from App.Xaml.cs?
An ItemTemplateSelector is a perfectly valid way of showing a different view (or portion of a view) for (possibly disparate) items that are shown in a list. Under the hood this is an implementation of a strategy pattern, where the view is chosen based on the data item.
However it seems that a tab view would also fit your criteria - as the command is triggered you instantiate a new tab for the required view. This view can be bound to the same viewmodel, so you could have changes from one tab being echoed on another tab. IIRC there are some tab view implementations that include something similar to a ItemTemplateSelector (because a tab view is a variation on a list control).
As for the IoC - don't be concerned about complexities there. Most IoC implementations will allow you to specify constructor parameter values or expressions as part of registering types.
Events occur in our Model and ViewModel that necessitate creating the appropriate View. The question is how to do this and avoid having any View code in the VM or M?
Here's the sequence of events so you can see this dilemma:
The user sets a number fields in a form to start a long running background process and then clicks the "Start" button. If this long running process succeeds then it needs to popup a chart with graphs to show the results. However, if the data fails processing for any reason then it can't popup charts, instead it logs an error message which is show in the a text box on the form.
Right now, that start button calls a method in the ViewModel which actually starts the background thread.
Only the background can determine when or if to create the view.
Currently we have this working by using an interface called ChartInterface. The view implements this interface and then sets a callback delegate all the way down to the backend model. When it decides to create the Chart it invokes the callback and uses the interface to pass the appropriate data and such.
However, this presents a problem because it can potentially produce dozens or hundreds of charts. So we need to have a "Dashboard" with a list of all the charts for the user to select which one to see.
So now the backend needs to decide when or if to create the Dashboard View, then add Chart View to it.
So it's getting messier because there will be increasingly more of these situations as we have lots of Models that need views so creating tons of callback delegates gets ugly fast.
An idea that seems to simplify instead of lots of callbacks will be to only pass an interface to a ViewBinder to the backend. Then each time it creates a model object, it can pass it to the ViewBinder to see if it wants to bind any view object to it.
Our thinking is that most any of the backend objects will be interesting (eventually) to monitor graphically. So if everyone of them after contructing is passed to the ViewBinder interface, then the view can decide if it wants to bind anything to it.
This is sounding better all the time.
The answer became clear while working on the code.
public interface ModelBinderInterface {
void TryBind( object model);
}
instead of one global "server locator" it's more natural for EVERY view object to implement this interface.
Then when it creates any ViewModel objects it assigns itself to the ModelBinder property of the the viewModel object.
Now the ViewModel can pass this same interface to the back end process.
When ever any relevant model gets instantiated, then it calls the ModelBinder with the object.
Then the View object can decide if it can instantiate the object, if not, it can pass the call up to it's parent which also implements ModelBinderInterface.
This way each view can handle instantiating views that it understand whether that be adding a control to a DataGridView or binding the object to a ListView, etc.
Of course, this still allows for a singleton ModelBinder because the lower levels can keep handing the call up to the top level application ModelBinder which there's only one and it can offer singleton instances.
I have a few questions regarding WPF commands.
Where should I put confirmation dialogs? Should I show them right inside the command callback function? What if in some areas in the application I don't want a command to show a confirmation?
If I have a user control that shows items that can be deleted. Should the command be in the application's view model, and I use it for the item deletion, or should the user control itself also have a command that in turn calls the view model's function? (Note: the application view model is the only one having the information needed to do this operation)
How can I pass data within a command? I am using mostly DelegateCommand, and upon firing a command for a grid item, I'd like to pass the selected item, otherwise the application's main view model would have to find the grid and figure out its selection which will hardcode the command to the grid and not make it reusable.
A bit of this is opinion and style . . . Here's my approach:
Question 1:
I have a utility class that handles any confirmation, and I use the lightweight messaging in MVVM Light to handle communication between the view, the confirmation, and the viewmodel.
Edit: A bit more information on point 1
From within my Command, I will send a message along the lines of
"ConfirmDeletionMessage", which is then picked up by my dialog utility
class. The dialog utility class displays the appropriate message to
the user, and checks the results. Based on the results, it will
either broadcast a "DeletionConfirmedMessage" or
"DeletionCanceledMessage," which is then handled by the ViewModel to
either complete or cancel the delete.
There is some risk involved if you have multiple subscribers to this
message, as you won't know what order they're going to be handled,
but if you have strict management on message consumers, or ensure
that they are able to run in a random order, this approach works
pretty well, and it separates your View and Model code in a testable
fashion.
Question 2:
This is a tough one, and it is going to depend on your overall application. I'm personally a fan of putting it in the item's viewmodel. That way, you don't have to worry about your third question as much. Instead, the delete action simply works on the item you're dealing with. However, if you have to act on data outside of your list item (like removing it from the list), it makes more sense for the command to be on the parent viewmodel.
Question 3:
Use the CommandParameter property. You can bind this to whatever you want.
EDIT to Answer #2
Mark Green (who commented below) got me thinking. I originally adopted this approach for WP7, and it absolutely suited what I needed to do. However, there are other ways of handling this that should absolutely be considered. Another option is a "confirmation class" that can be used by your viewmodel. If you are using an IoC kernel, this becomes easy to do with constructor / property injection. Alternatively, if you have other methods of getting the class, do so, but do it in a way that you can mock out in testing. It might look something like this:
public class ExampleViewmodel : ViewModel
{
private IConfirmDialogManager _dialogManager;
public ExampleViewmodel(IConfirmDialogManager dialog)
{
_dialogManager = dialog;
}
// ... code happens ...
private void DeleteCommand()
{
bool result = _dialogManager.Confirm("Are you sure you want to delete?");
}
}
With an IConfirmDialogManager interface that looks like this:
public interface IConfirmDialogManager
{
bool Confirm(string message);
}
Which you would then implement appropriately.
Where should I put confirmation dialogs? Should I show them right inside the command callback function? What if in some areas in the application I don't want a command to show a confirmation?
Confirmation dialogs and show message dialogs are views.
Your VM should have a way of notifying your view that it wants to display something or ask something, then the view should decide how to display it (status bar, window, pop-up, voice message, ...)
If I have a user control that shows items that can be deleted. Should the command be in the application's view model, and I use it for the item deletion, or should the user control itself also have a command that in turn calls the view model's function? (Note: the application view model is the only one having the information needed to do this operation)
The items control should raise a delete command. The VM should handle the command and decide what to do (the VM should have the list of the selected items and the view should be binding to that list).
How can I pass data within a command? I am using mostly DelegateCommand, and upon firing a command for a grid item, I'd like to pass the selected item, otherwise the application's main view model would have to find the grid and figure out its selection which will hardcode the command to the grid and not make it reusable.
Commands can have parameters (e.g. RoutedUICommand). The command binding can specify a binding expression for the parameter. However, the correct approach is for the VM to be the source of the selection with a two way binding between the view's selection and the VM's.
simply use a dialogservice in your viewmodel
it depends but nevertheless the object/viewmodel where the command is located can easily reached with RelativeSource binding
CommandParameter is one way. in fact you use mvvm all information you need should be bind to your viewmodel. so if you have a command and you need the selecteditem from a listview, you can bind it to the viewmodel and dont need to set this as commandparameter
First off let me say this is my first attempt into trying MVP. I am going for the Passive View approach as I want to completely decouple the Views from the Model.
I have read up on MVP by reading the following articles among others
Derek Greer
http://aspiringcraftsman.com/2007/08/25/interactive-application-architecture/
Todd Snyder
http://blogs.infragistics.com/blogs/todd_snyder/archive/2007/10/17/mvc-or-mvp-pattern-whats-the-difference.aspx
My application is going to have 4 Views that are custom controls in which each implement a different interface to interact with the Presenter. Now this is not a problem for 3 of the views as the controls are static and never change.
My problem comes along where on the 4th View I need to change the control/View that is displayed based on events triggered from View 1.
So for example lets say View 1 is a list of people who can be from either an employee or a customer. Now depending on who is selected you can modify different parameters depending on the type of person selected. The problem is that View 4 needs to dynamically change the editing control based on what is selected. Keep in mind not only the properties will be different but how they are edited as well. Also each editing control is going to fire different events for property changes.
So how does my Presenter know how to manage interaction with the Model, when depending on whether an employee or customer is selected there is a different editor that implements a different View interface?
I hope that was clear. Any help is greatly appreciated. I have searched all over and all examples show a concrete relationship between the View and Presenter whereas mine needs to be extremely flexible.
My goal here is to keep the editing controls on the 4th View so flexible that I could for example add editing controls/Views for aliens or dogs or whatever else I might add to View1 to be selected.
Thanks
You can create a top-level presenter that listens for selection events and changes the editing control by instantiating different MVP triads based on what is selected. Typically in MVP your presenters manage all the construction/dependencies.
I personally don't like having a 'Master Presenter' per se. I do build composite presenters: e.g. View can contain one of several views, so I build a Presenter for the master view, which sends commands (messages, events, whatever) to a specific child presenter (I don't expose any View outside it's owning Presenter).
Don't over-complicate things ...use a different View for each responsibility. Views are cheap.
(Note: I chose to not use the Navigation Framework)
I have a WizardViewModel which is linked to WizardView.
The WizardViewModel declares and instantiates a command "Next".
It also contains a Property "ActiveSpell" of Type SpellViewModel.
The SpellViewModel contains several PageViewModels, each having a View counterpart.
The ActivePage Property (on SpellViewModel) tells the ui which view to take.
Now I have the following problem:
When I click a button to switch to the next page,
I need access to the "Next" command defined in the WizardViewModel,
but I only have access to a PageViewModel there.
I could just add a Parent property to each child ViewModel,
but I'm not sure if that is a good idea.
Or maybe there is another nicer/common way to do that.
You can use Event Aggregator, to adjust the interaction between ViewModels.
You don't need Parent property. Your view model structure is good, just look at the picture, to understand how you should bind your view model onto the view:
Next command should be implemented something like that:
public void NextExecute()
{
ActualSpell.MoveToNextPage();
}
UPDATE:
According to your comment, Arokh, I've updated the post.
I think, in this case you should implement ActivateCreatePersonSpell command in WizardViewModel.This command should:
save actual spell state
open CreatePerson spell
once person is created set saved spell with result of creation person
The last what you need to do is to bind ActivateCreatePersonSpell command to button on the page. I propose to use ViewModelLocator for these purposes.Look at this post for example.
I had to implement a wizard once and I liked and mimicked the way Josh Smith and Karl Shifflett set up their WizardViewModel and wizard page view models in this example project (source code available with the article):
http://www.codeproject.com/KB/WPF/InternationalizedWizard.aspx
They kept the Next command as part of their WizardViewModel, but created a WizardPageViewModelBase that all of the wizard pages derive from. That allowed the WizardViewModel to control which page is the current page, and it allowed the WizardViewModel to query the current page view model to see if the Next command can execute, thus enabling or disabling the Next button on the wizard. (That is, the wizard view model knew about the page view models, but the page view models didn't need to know anything about the "parent" wizard view model.)
As for adding links to parent view models, it's an approach that works, and I've done it before when I started working with MVVM, but after time I found the approach to result in some difficult to maintain code as every view model becomes interdependent.