tags:

views:

1057

answers:

2

So I've seen that a Navigation Service exists in WPF for maintaining a flow through an application. I'm not really in the market for the back and forward type functionality. I'm just looking for a good way to switch between Views when a button on a particular view is pressed. I'm using MVVM, so I'm not sure if I can let the App.xaml.cs possibly contain a copy of each View or ViewModel and let a ViewModel command call into App.xaml.cs to do the switching. Perhaps I should just handle the Click event on the button and do some flavor of this.Close(); NewWindow.Show();.
As with many things in WPF, this one is not intuitive to me although there probably are a couple simple solutions.

Thanks!

+2  A: 

I created a "window loader" class that the app class instantiates when the application starts. The window loader has a dictionary that maintains an association of view model types and view types. It also has a method that takes a view model instance, resolves the view based on the view model's type, instantites the view, sets the view's datacontext to the view model then shows it. The window loader also registers for an event in the view model which is raised when the window wants to close.

The window loader implements an IWindowLoader interface and a reference to it is kept in each view model (when the window loader instantiates a view model it assigns itself to a public IWindowLoader property in the view model). So any view model can cause any other view model to be shown without knowing about views and without doing the showing itself. Also, the window loader can easily be mocked for testing.

When I went through the same process you are now, I found lots of examples of this same basic pattern. I just ended up rolling my own.

MarkB
Sounds pretty reasonable. I get the event for the window closing. How did you wire the call to open a new window of one of the registered types? Also an event on the window loader? Did you pass the type to open as a string and let the windowloader resolve it to a type?
Bob
Opening a new window: every view model has an IWindowLoader property. And every view model (even the main window's) is instantiated by the window loader in the app class. So when the window loader creates the view model, it just does viewModel.WindowLoader = this.Then viewModel1 can do:ViewModel2 viewModel = new ViewModel2();this.WindowLoader.Show(viewModel);Then the window loader Show method looks up typeof(viewModel) in the dictionary and uses Activator to instantiate the view, marry the two together, register for the close event and does a window.Show().
MarkB
Minor correction: the window loader looks up a viewModel.GetType(), not a typeof(viewModel). Also, contrary to my original answer, my window loader Show method does not take the type of the view model to show but an instance of it. The reason for this is that I liked having my "parent" view models instantiate their own children so that they could set properties and do any other preparation as needed before passing off to the window loader.
MarkB
I like it. Thanks.
Bob
Well, actually I *almost* get it. What does the CloseWindow event in the WindowLoader take as an argument? I cant figure how to get the reference to the instance of the window to close back into the WindowLoader, unless its supposed to somehow keep a copy of all the open windows?
Bob
The window loader does not maintain references to open windows. Instead, it adds a delegate to an EventHandler in the view model instance it is given before it shows the window. That looks like this: viewModel.RequestClose += delegate(object sender, EventArgs e) { window.Close(); };
MarkB
+1  A: 

A way to solve this is to introduce Controllers which are responsible for the workflow of the application. They create, show and close multiple views in the application.

How this works can be seen in the sample applications of the WPF Application Framework (WAF) project.

jbe
for other reasons, I had to scrap the window loader and did actually end up writing a static controller class, that any of my view models can subscribe to if they want to do stuff when user control navigation changes. And my main window performs the actual switch by binding the visibility of the individual user controls to the CurrentNavigation property in a DataTrigger.
Bob