WPF+Unity: UserControl with usage of services? - wpf

I've an UserControl, which basically looks like this:
You guessed, the goal is to allow the user to choose a file/folder when clicking on Browseand then display the file path in the TextBox.
I started my first fully MVVM application(Using Prism+Unity), and I have in fact an IDialogService which allows me to show a MessageBox, but also display some OpenFileDialog and SaveFileDialog.
I would like to use the implementation provided for this IDialogService in order to display to the user my dialog box once the Browse command is executed.
Since the UserControl isn't built with Unity, how to request the implementation ?

If I understand you correctly, your UserControl needs to get hold of the Unity container you're using, one way or another. If you're instantiating the UserControl yourself, you can consider adding it as a constructor parameter; if it's instantiated by the framework you could consider a Container property or a setter method. Or you could go with the container as a singleton.
Either way, assuming your UserControl has a field like so...
IUnityContainer container;
...and that you've managed to point it to the container you're using, you should be able to resolve your service the normal way:
IDialogService service = container.Resolve<IDialogService>();
service.OpenFileDialog(...);

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.

ViewModel-first approach to Silverlight navigation

I am looking for a truly decoupled way of supporting navigation in a Silverlight application using MVVM. I am trying to accomplish more of a "purist" implementation of the pattern where the UI is completely separated from the ViewModels so that the application can actually run entirely without a UI. To do this, I need to support navigation without UI concerns.
I have several ideas how to accomplish this (with Messaging, etc) but haven't come up with a good way of "mapping" the View to the ViewModel so that the UI can show the appropriate View when the ViewModel is "displayed". I recall coming across an article some time ago that described a solution to this very problem but can't seem to locate it online anymore.
Does anyone know how to find this article or have any experience solving this problem?
So here's my somewhat long-winded description what we ended up doing:
First, we decided to use the built-in Page Navigation framework. We had multiple reasons but since it is built-in and is also the navigation framework du jour in Windows 8, we opted to try this approach.
I should also mention that we use MVVM Light and MEF in our applications. (This comes into play below.)
To make this work, we created an application Shell (UserControl) that contains the Frame control. The Shell's DataContext is set to an instance of the ShellViewModel which exposes a single CurrentPage property (of type String). We then bind the Frame's Source property to CurrentPage. This approach is similar to Rachel's app-level ViewModel.
The ShellViewModel registers with the Messenger to receive CurrentPageChanged messages. When the message is received, the CurrentPage property is updated, the PropertyChanged event raised and the UI updated. The message originates from the NavigationService (which implements INavigationService and is injected/imported using MEF).
The NavigationService exposes a NavigateTo method which accepts the string name of the ViewModel representing the destination. This name matches the contract name applied to the ViewModel when exported (using MEF) and used to lookup the instance using our ViewModelLocator.
In the NavigateTo method, we use the ViewModelLocator to retrieve the ViewModel instance, call Deactivate on the current ViewModel (if one), call Activate on the new ViewModel then send the CurrentPageChanged message with the name of the new view as a parameter. Activate/Deactivate are helper methods on the ViewModels that allow us to perform any necessary tasks when the ViewModel is navigated to or from.
This appears to be working well and gives us a very MVVM-ish implementation with all navigation isolated from our ViewModels via the INavigationService and messaging.
The only down-side right now is that while we are using string constants in code to represent the ViewModel names, we are still hard-coding the strings in the Views to set the DataContext. I will be looking into a way to set the DataContext automatically as part of the navigation 'tooling'.
I should mention that this approach was parsed together from a number of sources, including (but not limited to) Rachel and the following links:
http://blogs.microsoft.co.il/blogs/eladkatz/archive/2011/01/25/adapting-silverlight-navigation-to-mvvm.aspx
http://blog.galasoft.ch/archive/2011/01/06/navigation-in-a-wp7-application-with-mvvm-light.aspx
http://www.geoffhudik.com/tech/2010/10/10/another-wp7-navigation-approach-with-mvvm.html
Usually I have a ViewModel for the entire app, and it contains the CurrentPage and all navigation event handling.
On the View side, I use a ContentControl with it's Content bound to CurrentPage, and use a DataTemplateSelector to determine which View to display for which ViewModel
There's an example here if you're interested, although it uses DataTemplates instead of a DataTemplateSelector.

How to call a user control method using MVVM?

I'm working in a WPF project, I'm using the MVVM patter in my project.
I created a user control (also in WPF) and I want to use it in my project, now, my problem is that I have a method in my user control that I need to call from my View Model, but I don't know how to do that, how to bind to the method inside my control from the view model.
If I use code behind, obviously there is no problem since I have a direct reference to my control, so I can do "mycontrol.MyMethod();"m, but of course, doing in this way will go against the logic of the MVVM pattern.
I tried to use a Dependency Property in my user control, and use that Dependency Property to bind to it in the xaml of my project but it didn't worked, the compiler says that the property was not found or is not serializable.
So I will appreciate if someone can share some light about how can I accomplish this.
Edited
As far as I understand you have the view, which is all the GUI, then you have the model, which is all the logic, and them you have the view-model which is like an intermediate layer used to bind the view with the model, right?
In this way I have developed my project, however I came to the problem that I need a custom control, a TextBox that remember what the user entered, and when he start typing, if there are words that start with that letter, those words are shown as a suggestion, as Google does it.
This TextBox is used as a search filter; so I created a user control to do this, I added a method to my user control to allow whatever application that uses my control to add items to an internal array that holds all the strings that the user has entered.
I created a user control because I couldn't find any control that behaves the way I want.
So my problem is when I add my user control to the main project, because I need to someway be able to call the method that add the items to the internal array, but maybe I'm doing things the wrong way, so if any of you has a better idea, I will appreciate if you shared it with me.
You should never call View methods from ViewModel, and vice versa.
Make a property (ObservableCollection?) on your ViewModel, it will have CollectionChanged event, subscribe to it to monitor changes (if needed).
When you add an item to the collection in your ViewModel, GUI will be updated accordingly (you have to perform the Add() operation on GUI thread, btw).
If you need to change the current position in your list, there are colections for that (CollectionViewSource, etc).
If you really really need to pass a string to your control, make a DependencyProperty and bind it OneWay to your ViewModel's property. When you set the value, it will call PropertyChangedCallback on your DependencyProperty.
Why does the consumer of the user control need to maintain the control's internal array? That seems like you've exposed an implementation detail that you don't need to.
Why not simply make that array a dependency property (and an IEnumerable<string> or ObservableCollection<string> besides)? Then you can simply create the corresponding property in your view model and bind it to the control. It also makes the control considerably more versatile.
You shouldn't call something in the View from the ViewModel since that breaks the model.
If the reason you want to call the method in the user control is to do with UI only, I don't see anything wrong with doing it from the view - the view's cs and the view's xaml are in the same "space" in the model. You can be overly-purist in wanting to have lean and mean view cs files.

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

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.

Resources