How do I get the NavigationService without being a Page? - silverlight

This seems to be a really naive question, but how on earth does one get the NavigationService from outside of a page, like say perhaps a view model? Everybody says that navigation should occur at the view, but I keep thinking, this is not a web page, its an application. The view model and business logic should control application flow, not the view. Is this in fact naive?

As far as I understand it, operations involving the View, i.e. UI, should be done by the View exclusively. When working with MVVM, the UI should not be controlled by the ViewModel or BusinessLogic directly (since they are not supposed to know anything about the concrete implementation of the View) but work with Messages.
That means, if we want to open an Editor window from the ViewModel we send a Message from the ViewModel that we want to open it and receive it in the View and open the window there. The same is valid for Navigating through different pages, where you would receive the Message in the MainPage (or whatever holds you pages that you want to navigate through) and handle everything there.
An alternative to that would be using a DialogService or something like that, which handles opening windows in a central place. However, since the NavigationService is a property of the Page class, we need to handle the message in the Page.
Example code, using the MVVM Light Toolkit: (not tested, partly taken from Shawn Wildermuth's RiaXBoxGames example):
ViewModel (e.g., put that in a Command for a Button):
Messenger.Default.Send<bool>(true, "GoToNextPage");
View (e.g. put that in a Constructor):
Messenger.Default.Register<bool>(this, "GoToNextPage", ignore =>
{
// your code to go to next page
});

another option is to create an event on ViewModel, fire this event when Command occurs and subscribe View to this event. Inside EventArgs you can carry which page to navigate to etc. I think simple and testable solution.
Robert

I just pass a reference to the Frame when I create the View-Model.

Related

Using MVVM in WPF, should I launch child windows from View code behind, or ViewModel?

I've been puzzled by this for a while. I am writing quite a large RibbonWindow WPF application using the MVVM pattern. The screen has a RibbonBar menu along the top and the rest of it displays the various Views. Some Views contain other Views and some of these have buttons that launch child Windows.
So far, I have been doing this from the View code behind file, but I'm aware that these files are supposed to be empty when using MVVM. I could move the child window launch code to the ViewModel, but then I would need a reference to the main RibbonWindow (to set as the child window owner) and that doesn't seem right.
Any advice or tips on how this is normally achieved using MVVM would be greatly appreciated.
I usually handle this by creating some sort of WindowViewLoaderService. When your program initializes you register your Window's and your ViewModels with code something like this:
WindowViewLoaderService.Register(TypeOf(MainWindowView), TypeOf(MainWindowViewModel));
WindowViewLoaderService.Register(TypeOf(MyWindowView), TypeOf(MyWindowViewModel));
Then when you can for example call into this service from your ViewModel and all you have to reference is your other ViewModel. For example if you are in your MainWindowViewModel you might have code like this:
var myChildWindowVM = new MyWindowViewModel();
WindowViewLoaderService.ShowWindow(myChildWindowVM);
The WindowViewLoaderService would then look up what View is associated with the specified ViewModel you passed it. It will create that View, Set its DataContext to the ViewModel you passed in, and then display the View.
This way your ViewModels never know about any Views.
You can roll your own one of these services pretty easily. All it needs to do is keep a Dictionary with the key being your ViewModelType and the value being your ViewType. The Register method adds to your dictionary and the ShowWindow method looks up the correct view based on the ViewModel passed in, creates the view, sets the DataContext, and then calls Show on it.
Most MVVM Frameworks provide something like this for you out of the box. For example Caliburn has a slick one that just uses naming convention its called ViewLocator in this Framework. Here is a link that summarizes: http://devlicio.us/blogs/rob_eisenberg/archive/2010/07/04/mvvm-study-segue-introducing-caliburn-micro.aspx
Cinch on the other hand calls it a WPFUIVisualizerService which you can see in action here:
http://www.codeproject.com/KB/WPF/CinchIII.aspx
These should help get you rolling.
Well, one remark to start with is that, "Having no code AT ALL in the code-behind" is actually a "myth". If you want to be pragmatic, and you see that having some code (as little as possible would be better), will make your life easier and solve your problem, then you should go with that.
However, in this situation, there are actually some loosely coupled ways to do this. You could have a service that does the interaction for you. You initiate the interaction with the user from the ViewModel, the service takes care of that (by showing a ChildWindow for example), and gives you back the user's reponse. That service can be mocked for testing easily. And it can be tested seperately.
That is, if you want to do things yourself. If you want a framework to do the heavy lifting for you, you can check out the InteractionRequest functionaity offered by Prism. Here's the MSDN article that talks about adanced MVVM scenarios which includes a section on User Interaction Patterns. That's the way I do it, and it's pretty simple, elegant and straightforward.
Hope this helps :)
To take Matt's answer one step further, you can have all your view's be a user control. Then create a ViewContainer, which is a window with your data templates (as you described).
Then you just ship the viewmodel you wish to open over to the window service, which sets the DataContext. The service would then open the window and the contentcontrol will resolve the correct view for the viewmodel.
This means all the registration is done in the XAML and the window service just knows how to do just that...open and close windows.
This is an old post, but maybe this'll help someone along the way: I use MVVM, and raise events for opening child windows from the ViewModel back to the View. The only code behind is handling the event, opening the window, setting owner of the child window and that's pretty much it. In the viewmodel, if the eventhandler is null, then it's not subscribed to by the view and doesn't fire. The VM does not know about the view. The code is pretty simple also and only takes a few lines.
In this situation View should handle the opening of the child windows.
However, ViewModel might drive the creation of the windows, but calling into View to create a new Windows.
This will save the logic of MVVM pattern: ViewModel has the "brains" but is not involved in a particular window creation.
ViewModel only is used to present system state and UI logic. One viewmodel may be referenced by multiple views. It have no knowledge of UI specific code like parent/child relationship, position, layout, size etc. So it is better to pop child window in view's code-behind with ViewModel's state changed event or command event and event arguments. In this way you can specify which one is the parent view in the UI layer.

Main page xaml to manage user control events

I need an elegant solution (I am working on silverlight 4.0) to solve this simple problem(?) using the MVVM pattern:
My mainpage xaml has my two custom user controls like this (say):
<uc:MyCustomUC1>
<uc:MyCustomUC2>
Each one has its own view model and both these user controls are independent of each other.
When an asynchronous operation in MyCustomUC1 has completed, I want an ICommand in MyCustomUC2's viewmodel to be invoked thus refreshing data in MyCustomUC2. I want this done by the parent page and all in xaml.
Exposing dependency properties, event handlers etc in the user controls...anything is ok since I own the user control ...whatever makes sense.
Any ideas ?
Use Mvvm Lights messenger, you can register a listener in MyCustomUC2's viewmodel to refresh. Then in MyCustomUC1's async call back, send the message to refresh.
You could use a PropertyObserver, which I believe you can find info on here:
Property Observer.
It'll allow you to check when something has changed in one ViewModel and then take the appropriate action in another. I've used this quite a bit recently in a project and it has worked pretty well.
Apologies if I've picked up the question incorrectly.

Is it right to call Navigate to other page from ViewModel?

I know there is many ways to Navigate to other page from ViewModel.
I'm not sure is this a good idea or not, since MVVM's purpose is to separate View from ViewModel, but Navigate to other page within ViewModel mean there's a couple between View and ViewModel, that being said, if I change View name, I need to change URI (string) in ViewModel too.
I want to know, is it right to call Navigate to other page from ViewModel? If it's wrong, what's the correct (or better) way to navigate to other page?
It's both right and natural.
When you make a navigation request, the "name" you provide as part of the Uri is the name with which your View class has been registered in the container. Since registering classes with the container is done by the module itself and not the View or the ViewModel, you are not introducing coupling between the View and ViewModel.
That said, if you want to customize the way that Prism interprets your navigation requests, you can always write a class implementing IRegionNavigationContentLoader. If you register this into the container, Prism will resolve your own class instead of the built-in RegionNavigationContentLoader. But it's not the simplest thing in the world to do.
Why don't you create a separate class that will keep the logic for navigation? In that case you'll only need to send a message from ViewModel that program should change the View and details would be decided arbitrally. With that approach you still have no direct connection between View and VM

Shell StatusBar UserControl communication

I have a wpf main window as the application shell containing status bar and a tab control with two tab items.
I have also two User controls and their View Model objects using MVVM.
I placed each user control on a tab item in the application shell.
My question is, I want the user controls to update the status bar on the main shell. What is the best way to handle that?
Thanks
I have the same question.
I don't know exactly what is the best way to do it but this my guess:
To me, the application class (I mean an override of it) is not right place to put it because it is too central. The status is per Window (Dialog).
Then, you could place it in the model of the Window but it is another bad idea (my opinion) because you will have to modify you model for something very virtual (status).
Personnaly, but I could be really wrong, I decided to declare a method in the parent window directly. Any model, if many, of any of my component that are part of that window could (preferably at initalization time) try to find the method (reflexion) and assign a delegate to it. Whenever you want to update the status you verifiy your delegate is not null and call it if its not. The delegate could be something like: SetStatus(string status). It's not perfect but it seems to respect hi cohesion and low coupling...
Hope it helps.
Eric
BXF (Basic XAML Framework)
http://bxf.codeplex.com/
From the BXF Documentation Page:
In its simplest form, Bxf acts as a message or request router from
application code to a presenter handler.
The idea is that your application code, typically your viewmodel code,
needs to do a set of basic things:
Show views
List item
Show status information

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