Model-View-Presenter and Modal Dialog boxes.... How to? - wpf

I am implementing MVP/M-V-VM in WPF and I'm having good luck with it so far. However, I don't see how this model supports implementing Modal dialog boxes. I've derived my work from Crack.NET (http://www.codeplex.com/cracknetproject) to learn how this stuff works.
I have a ShellView view (which is just XAML) that has a menu on it. The menu binds to a command in the ShellModelView that says "EditPreferences".
The ShellModelView implements the ICommand for EditPreferences and here we want to put up a dialog box to let the user edit preferences for the application.
Several problems here:
1. The ShellModelView doesn't have a reference to the ShellView to properly parent the dialog. The ShellModelView is the DataContext of the ShellView but I don't see a backreference that's setup.
2. The ShellModelView shouldn't be loading explicit UI anyway. So what's the proper interaction model here?
3. How do I build up my PreferencesDialog so that it's properly separated between logic and view as well? PreferencesDialog itself needs to be a Window so you can call ShowDialog on it, but that means you need a reference to the Window (e.g. View) in order to instantiate it. Ideally I should be able to unit test the code/validation within PreferencesDialog without instantiating the view (using a Mock view perhaps?).

Perhaps this is not the appropriate way to look at it, but this is the approach I take with M-V-VM in WPF. Opening windows and dialog boxes or an "EditPreferences" view are UI specific functions. If I were to rewrite the your entire UI replacing all of the views, I may wind up combining the "EditPreferences" view with another view, and therefore never want to open it in another screen. If this were tied to the ViewModel, it would be difficult to get around. In this particular situation, I would have a button or menu item in my "ShellView" that creates a new instance of my "EditPreferences" view, and then passes in the "EditPreferences" ViewModel which may either come from a property in my "ShellViewModel", or perhaps my "EditPreferences" view instantiates the ViewModel itself.
Here is a similar question on SO that basically says the same thing: M-V-VM Design Question. Calling View from ViewModel

You will need a controller in your case. The controller should be in charge for showing the preference dialog window.
As I can envision it the controller should be responsible for creating the ShellModelView and binding view's DataContext to it. The controller should be also responsible for handling command execution of EditPreferences. In the execution logic the controller will create a new PreferencesDialog and its corresponding view model.
You can find similar patterns in Prism if you haven't already did it. You can also reuse the DelegateCommand provided there :)

Have the PreferencesDialog implement a interface that is one of the properties of the EditPreference command. The command would interact with the dialog through the interface. For Unit Testing the mock object would implement the interface instead.
The dialog class then can reside on your highest layer.

My 2 cents is:
Pass some kind of viewfactory contract as the command parameter or inject a viewfactory contract into the view model. The view model will them use the viewfactory to create any modal/non modal views it needs. The viewfactory could also take in as a parameter of its Show/ShowModal method a viewmodel to display. Furthermore, the viewfactory could use a datatemplate to display any viewmodal passed in as a parameter.
Add a ShowViewModel property to the viewmodel in question. A DataTrigger could then watch for this property and when it is of a particular type show the view, etc.

Related

How to open a modal window the MVVM way

I'm still trying to get a grip with WPF and MVVM and stumbled upon questions, where the easy way seems to violate the MVVM rules.
As far as I understood it, in MVVM the view model is not allowed to know about the view. So if I put views and view models in different assemblies, the view model assembly is not allowed to reference the view assembly.
So, here are my questions:
Let's say I have a MainView and a corresponding MainViewModel. The MainView has a button that is supposed to close the window and do some serious stuff before closing (for instance saving data and configurations).
This button is bound to a CloseCommand in the MainViewModel, but how do I know in the MainViewModel which view to close.
My easy (and wrong) ways would be either to give the MainViewModel an instance of the MainView on initialisation or to give the view-to-close as a command parameter.
But both solutions violate the MVVM rule.
Let's say my MainView contains a TextBox bound to a string property of my MainViewModel. If the text, the user types in the TextBox, isn't unique enough, I'd like to open a new modal window in which the user can select his input out of various choices.
To open a modal window in WPF you have to put the MainView in the Owner property of the new window. Therefore you need a reference to the MainView in the MainViewModel.
Same problem exists, if you try to show a modal message box (a message box that is tied to the parent window and can't be put behind the parent window through mouse clicks or other user actions).
So, how is one supposed to do actions in the view model when you need knowledge about the view?
Thanks for your help.
It seems that you wish to close the main window, and that is perfectly fine. As many things, this can be solved with a new level of abstraction. Lets say you have an interface called IApplication with a method Close(). And then lets say you have an implementation of the interface that might look something like:
class ApplicationWrapper : IApplication
{
public void Close()
{
Application.Current.MainWindow.Close();
}
}
Couldn't you inject the IApplication interface in the view model and call its Close method from the command?
I would propose MVVM Dialogs, but I am biased since I also am the author.

WPf, MEF Architecture design

i faced with some problems when designing architecture of my extensible programm.
I'm using MEF, MMVM Light Toolkit and AvalonDock.
The first problem is how display view for some ViewModel imported from another assembly using MEF.
To solve it, i'm exporting ResourceDictionary where i'm defining DataTemplate's for views declared in this assembly.
Dictionary:
<ResourceDictionary
...>
<DataTemplate DataType="viewmodels:MyViewModel">
<views:MyViewForViewModel/>
</DataTemplate>
</ResourceDictionary>
And in constructor of MainWindow i'm importing all ResourceDictionaries and merging them with MainWidow.ResourceDictionary.
Is it good? It's also possible to specify 'scope' of ResourceDictionary to import it not to MainWindow, but to Application for example.
The second problem is ICommands and CommandBindings.
To populate Menu i'm exporting 'MenuItems' where i'm defining ICommand, Text and other stuff, but i don't know how to export CommandBinding, should i use RelayCommand for cases when i can't create CommandBinding?
The third problem is dialogs.
I found great article Showing Dialogs When Using the MVVM Pattern and easily adapt it to MEF. But, for example, I have an IDatabaseService which don't have any View.
The Workspace, main ViewModel, storing instance of IDatabaseService and creating menu item: Connect to Database. Using IDialogService Workspace opening some imported IConnectToDbDialog so Workspace don't know anything about it. When dialog closed, the SqlConnectionString should be passed to IDatabaseService.
So who must pass this SqlConnectionString, IConnectToDbDialog or Workspace.
The fourth problem is how to communicate with IDatabaseService correctly.
For example. In some View i have Button: 'Create Item In Database'. And how should i call IDatabaseService method CreateItem(ElementType elementType) when button clicked?
The problem, that there are a lot of buttons which create Items with different ElementType in database, so, i think, it's right to create some ICommand with parametr and create only one handler for this command which will invoke some method in IDatabaseService. But i don't know how.
The other solution is to send messages to IDatabaseService from ViewModel to create item.
which way better?
Try to answer your questions.
It is good. You can merge either on XAML or code behind but I prefer XAML. You can put it on MainWindow.Xaml, which is in scope of main window or on App.Xaml, which is in application scope.
I did not export views before. In my opinion, if you put CommandBindings under Menu, it does not matter when it is exported then imported if the event handler in the scope of imported environment.
It depends. Theoretically you can put the service call in either owner's view model or dialog's view model. If your dialog have a create/submit button, for instance, and you expect the dialog keeps alive until submission is successful, then put it in dialog's view model so that you can keep it open when you handle exceptions. if you do not need the dialog keeps open, then you can put the logic in owner's view model after dialog is closed.
Command is better. Considering the view model gets IDatabaseService object from IoC container, You might have one ICommand property that accepts ElementType parameter or a paramerter can map to ElementType. In the execute method you call CreateItem passing the parameter directly or from mapper. On you XAML, you put type in the command binding. Does it make sense?
Hope it can help.

Should a ViewModel in MVVM reference the View?

In the MVVM (Model-View-ViewModel) pattern should the ViewModel reference the view. I would think that it should not. But how should the following scenario be handeled? I have a view that has a tab control as the main container, the viewmodel for this view implements a command to add a new tab to the tab control. The easy way would be to allow the viewmodel to reference the view and then in the command implementation to just programmatically add the new tab to the tabcontrol in the view. This just seems wrong. Should I somehow bind the tabcontrol to the viewmodel and then implement a data/control-template to add the new tabs. I hope this makes some kind of sense to somebody :)
In "pure" MVVM, the ViewModel shouldn't really reference the View. It's often convenient, however, to provide some form of interface in the View whereby the ViewModel can interact with it.
However, I've found that I almost never do that anymore. The alternative approach is to use some form of attached property or blend behavior within your View, and bind it to your ViewModel properties. This allows you to keep the View logic 100% within the View. In addition, by creating a behavior for this, you create a reusable type that can be used to handle this in every ViewModel->View interaction. I strongly prefer this approach over having any View logic within the ViewModel.
In order to demonstrate this technique, I wrote a sample for the Expression Code Gallery called WindowCloseBehavior. It demonstrates how you can use a Behavior within the View bound to properties in the ViewModel to handle controlling a Window's life-cycle, including preventing it from being closed, etc.
Reed and Dan covered the general approach but in reference to your specific case, TabControl is an ItemsControl and so can bind its ItemsSource to a data collection in your ViewModel representing the set of tabs to display. The UI for each type of tab can then be represented by a DataTemplate specific to the data type of an item (either using DataType or a DataTemplateSelector). You can then add or remove data items as needed from your VM and have the tabs update automatically without the VM knowing anything about the TabControl.
I find that it's often a helpful compromise to expose an interface on the View that handles View-specific functionality. This is a good way to handle things that are awkward to accomplish with pure binding, such as instructing the form to close, opening a file dialog (though this often gets put in its own service interface) or interacting with controls not designed well for data binding (such as the example you provided.)
Using an interface still keeps the View and ViewModel largely decoupled and enables you to mock the specific IView during testing.
One of us is missing something obvious. Your tab control is an ItemsControl. You should bind the ItemsSource of your tab control to an ovservable collection in your view model. When you handle the command in your view model to add a tab, you simply add a new element to this collection and, voila, you've added a new tab to the control.

StockTrader RI > Controllers, Presenters, WTF?

I am currently learning how to make advanced usage of WPF via the Prism (Composite WPF) project.
I watch many videos and examples and the demo application StockTraderRI makes me ask this question:
What is the exact role of each of the following part?
SomethingService: Ok, this is something to manage data
SomethingView: Ok, this is what's displayed
SomethingPresentationModel: Ok, this contains data and commands for the view to bind to (equivalent to a ViewModel).
SomethingPresenter: I don't really understand it's usage
SomethingController: Don't understand too
I saw that a Presenter and a Controller are not necessary but I would like to understand why they are here. Can someone tell me their role and when to use them?
I had exactly the same problem when I first went through Prism.
Controllers are basically for logic that spans an entire module, whereas Presenters are for logic that is specific to a View.
For example, a Presenter would respond to a command that results in a button in the view being disabled. A Controller would respond to a command that results in the View (and Presenter) being changed entirely, or perhaps loading a different View/Presenter in a different region in the module's shell.
Edit: As for when to use them, you can skip the Controller entirely if you have no need for the orchestration mentioned above. The simplest application will just have a:
Module: registers the view/presenter into the Region
Presenter: responds to commands from the view and modifies the ViewModel.
ViewModel: adapter between Presenter and View that implements INotifyPropertyChanged
View: binds to ViewModel and displays UI
Edit: As for Presenter vs ViewModel, most of your logic should be in your Presenter. Think of your ViewModel as housing the logic for your view, but the Presenter as dealing with the consequences of interacting with the view.
For example, the user clicks the "Search" button in your View. This triggers an ICommand, which is handled by your Presenter. The Presenter begins the search and sets the ViewModel.IsSearching property, which fires the PropertyChanged notification for CanSearch. CanSearch is a readonly property that is based on several other properties (eg. IsSearchEnabled && !IsSearching). The "Search" button in the View has its Enabled property bound to CanSearch.
In my opinion Controller in here refers to Application Controller

Open dialog in WPF MVVM

I have an application that need to open a dialog from a button where the user enters some information.
At the moment I do it like this (which works fine)
The button click generates a command in the ViewModel.
The ViewModel raises an event which the Controller listens to.
The Controller works out the details of the new window (i.e. View, ViewModel & model) and opens it (ShowDialog)
When the window is closed the Controller adds the result to the eventargs and returns to the ViewModel
The ViewModel passes the information to the Model.
There are a lot of steps but they all make sense and there is not much typing.
The code looks like this (the window asks for the user's name)
ViewModel:
AskUserNameCommand = DelegateCommand(AskUserNameExecute);
...
public event EventHandler<AskUserEventArgs> AskUserName;
void AskUserNameExecute(object arg) {
var e = new AskUserNameEventArgs();
AskUserName(this, e);
mModel.SetUserName(e.UserName);
}
Controller:
mViewModel.AskUserName += (sender,e) => {
var view = container.Resolve<IAskUserNameView>();
var model = container.Resolve<IAskUserNameModel>();
var viewmodel = container.Resolve<IAskUserNameViewModel>(view, model);
if (dlg.ShowDialog() ?? false)
e.UserName = model.UserName;
}
My question is how the horizontal communication works in the MVVM pattern.
Somehow it seems wrong to let the controller be involved in the data transfer between the models.
I have looked at the mediator pattern to let the models communicate directly. Don't like that idea since it makes the model depending on implemetations details of the GUI. (i.e. if the dialog is replaced with a textbox, the model need to change)
I don't like most of the current suggestions for one reason or another, so I thought I would link to a nearly identical question with answers I do like:
Open File Dialog MVVM
Specifically the answer by Cameron MacFarland is exactly what I do. A service provided via an interface to provide IO and/or user interaction is the way to go here, for the following reasons:
It is testable
It abstracts away the implementation of any dialogs so that your strategy for handling these types of things can be changed without affecting constituent code
Does not rely on any communication patterns. A lot of suggestions you see out there rely on a mediator, like the Event Aggregator. These solutions rely on implementing two-way communication with partners on the other side of the mediator, which is both hard to implement and a very loose contract.
ViewModels remain autonomous. I, like you, don't feel right given communication between the controller and the ViewModel. The ViewModel should remain autonomous if for no other reason that this eases testability.
Hope this helps.
i use this approach for dialogs with mvvm.
all i have do do now is call the following from my viewmodel to work with a dialog.
var result = this.uiDialogService.ShowDialog("Dialogwindow title goes here", dialogwindowVM);
I have come across similar problems. Here is how I have solved them, and why I have done what I have done.
My solution:
My MainWindowViewModel has a property of type ModalViewModelBase called Modal.
If my code needs a certain view to be modal, it puts a reference to it in this property. The MainWindowView watches this property through the INotifyPropertyChanged mechanism. If Modal is set to some VM, the MainWindowView class will take the VM and put it in a ModalView window where the appropriate UserControl will be shown through the magic of DataTemplates, the window is shown using ShowDialog. ModalViewModelBase has a property for DialogResult and a property called IsFinished. When IsFinished is set to true by the modal VM, the view closes.
I also have some special tricks for doing interactive things like this from backgroundworker threads that want to ask the user for input.
My reasoning:
The principle of modal views is that other views are disabled, while the modal is shown. This is a part of the logic of the View that is essentially lookless. That's why I have a property for it in the MainWindowViewModel. It I were to take it further, I should make every other property or command for all other VM's in the Main VM throw exceptions, while in modal mode, but I feel this to be excessive.
The View mechanism of actually denying the user any other actions, does not have to be performed with a popup window and showdialog, it could be that you put the modal view in the existing window, but disable all others, or some other thing. This view-related logic belongs in the view itself. (That a typical designer can't code for this logic, seems a secondary concern. We all need help some times.)
So that's how I have done it. I offer it only as a suggestion, there is probably other ways of thinking about it, and I hope you get more replies too.
I've used EventAggregator from Prism v2 in similar scenarios. Good thing about prims is that, you don't have to use entire framework in your MVVM application. You can extract EventAggregator functionality and use it along with your current setup.
You might have a look at this MVVM article. It describes how a controller can communicate with the ViewModel:
http://waf.codeplex.com/wikipage?title=Model-View-ViewModel%20Pattern&ProjectName=waf

Resources