How do I navigate from a ViewModel? - wpf

I am writing a small contrived WPF application for a university project, and i'm taking the opportunity to learn the MVVM pattern. I've implemented my initial start up window which will be a login page.
I have bound the login button to a command that I have derived from ICommand, which is injected with the LoginViewModel. The LoginViewModel then validates the customer through a WCF service I have created.
My question is, once the viewmodel receives notification that the validation is correct, how should I navigate to the next page/window from the viewmodel? I don't want to create an instance of a new window within the viewmodel. Should I be using pages here instead? I'm keen to understand the best practices from the start, I don't want to be wasting my time learning the bad ways of doing this.
Thanks.

Instead of changing views, you can change viewmodels and use a ContentControl to bind the viewmodels to specific views: create a main view on top of the other views which will manage the view changes via commands (in this example set the CurrentViewModel from your command handler):
<UserControl.Resources>
<DataTemplate DataType="{x:Type vm:LoginViewModel}">
<local:LoginView/>
</DataTemplate>
<DataTemplate DataType="{x:Type vm:FirstPageViewModel}">
<local:FirstPageView/>
</DataTemplate>
</UserControl.Resources>
<ContentControl Content="{Binding Path=CurrentViewModel}" />
This way you don't need to mix up the Views and ViewModels, you're not creating views from the VMs. Actually in my case it was the child page which requested the view change with an event.

I've not done pages, but for your login screen I would have my LoginViewModel expose a LoggedInEvent.
You can then have a parent ViewModel create the LoginViewModel and destroy it again when the LoggedInEvent is raised (and create whatever new views you need).

Related

WPF multiple views [duplicate]

I am working on a an WPF MVVM application where I need to have a Main Window with just a logo and it has to show child views inside it. I don't have any controls in Main Window all the controls reside in child view for example Buttons like Next, Back, Cancel and some text blocks etc. Now If users select Next button on the child view I have to draw or load the next child view inside the Main Window. If Back button is clicked I have to go back to the previous child view. So basically I am changing the child views depending on which button is clicked. Also I am maintaining different view models for every child view. Now the problem is I am not able to figure how should I link the child views to there respective view models. This application is similar to some Installation applications where different dialogs are shown depending on the selection and the button clicked by the user.I am new to this wpf and don't want to use MVVM Light , Prism etc. Any detailed help will be greatly appreciated. Thanks in advance.
One of the easiest ways to associate any data type with XAML controls is to use a DataTemplate. Therefore, you can simply add something like this into your Application.Resources and as long as you do not set the x:Key properties on the DataTemplates, then they will be explicitly applied by the Framework whenever it comes across instances of your view models:
<DataTemplate DataType="{x:Type ViewModels:HomeViewModel}">
<Views:HomeView />
</DataTemplate>
...
<DataTemplate DataType="{x:Type ViewModels:MainViewModel}">
<Views:MainView />
</DataTemplate>
Then displaying the view is as simple as this:
<ContentControl Content="{Binding YourViewModelProperty"} />
In code behind, or your view model:
YourViewModelProperty = new MainViewModel();
It's often handy to create a base class for your view models and then the YourViewModelProperty can of that type and you will be able to interchange them using the same property and ContentControl.
UPDATE >>>
The general idea is that you have one MainViewModel class with one BaseViewModel property data bound to one ContentControl in MainWindow.xaml... the navigation controls should also be in MainWindow.xaml and not in the views themselves. In this way, the MainViewModel class is responsible for changing the property to the relevant view model instances when it receives navigation Commands from the MainWindow.xaml.

mvvm Pass button click to parent

Note: this is a different question to the one here: Pass dependency property to child view
I am currently creating a usercontrol in wpf which consists of several 'screens' that the user will click through.
For each 'screen' I have created a view with it's own viewmodel (e.g. View1.xaml, View2.xaml). The main usercontrol can then access these views:
<UserControl.Resources>
<local:ModuleBaseViewModel x:Key="ViewModelDataSource" />
</UserControl.Resources>
<Grid x:Name="LayoutRoot" DataContext="{Binding Source={StaticResource ViewModelDataSource}}">
<local:View1 Visibility="Visible"/>
<local:View2 Visibility="Hidden"/>
</Grid>
I would like to pass a button click from a view back down to the parent usercontrol so that I can hide that view and show the next one. Can someone explain to me how to do this?
Thanks!
If you are using MVVM and WPF, chances are you are using an IoC container. Almost every IoC container contains a method of publishing an event and then subscribing to that event. In Prism, the code looks something like this:
EventAggregator.GetEvent<SomeEvent>().Publish(ParametersHere)
I would suggest you look at your options for publishing events and reacting to them. Then your parent view model can respond to the children's events.

Dynamically bind Views into a ContainerControl with MVVM

I've been learning the MVVM pattern with Josh Smith's article and I want to create a classic layout with some links to the right (managed with commands) so when I click one I can show my view to the right into a tab control (inside it there is a ContentControl).
This is simple when I use a DataTemplate with the specific View and ViewModel I want to show on screen like this.
<!-- this section into my MainWindow's resources file -->
<DataTemplate xmlns:vm='clr-namespace:WpfFramework.ViewModels'
xmlns:vw='clr-namespace:WpfFramework.Views'
DataType="{x:Type vm:MySpecificViewModel }" >
<vw:MySpecificView />
</DataTemplate>
But, I want something more generic. I mean that my mainWindow should not know a specific View nor a specific ViewModel. It should only know that it binds to some commands and has a tab control which shows "some view". Every sample including Josh Smith's article seems to have limited universe of views and viewmodels, that's great with a sample.
So, how can I tell my ContentControl that some view (with its corresponding viewModel) is gonna be there without being so specific (without "burning" into the mainView the concrete types)?
best regards
Rodrigo
PD. I have tryed with base a ViewModel and Base View but it doesn't seem to work.
In your main View, bind a ContentControl to a generic ViewModelBase property
<ContentControl Content="{Binding CurrentPage}" />
CurrentPage would be defined in the main ViewModel as a ViewModelBase object, and to switch pages you simply set CurrentPage to whatever you want.
So when you click on something like the HomePageCommand, the main ViewModel would execute CurrentPage = new HomePageViewModel(); providing that HomePageViewModel inherits from ViewModelBase.
I wrote something a little while ago that shows some samples here if you're interested

Why the view constructor is not called every time I create a new viewmodel?

I am using WPF with model-view-viewmodel pattern. I have a ResultsView and ResultsViewModel which are connected like this:
<DataTemplate DataType="{x:Type VM:ResultsViewModel}">
<VW:ResultsView/>
</DataTemplate>
In my main window I have some kind of paged setup where MainContent property stores the current page (ViewModel instance).
I create the page like this
MainContent = new ResultsViewModel();
ResultsView is based on UserControl, it also has a handler for Loaded event which does some UI initialization stuff.
Everything works fine while the user is navigating between different pages.
But if the user opens the ResultsView two times in a row, the ResultsView constructor is not called the second time, and also Loaded event is not called. It seems that now I have the same old ResultsView instance attached to the new ResultsViewModel()!
Why WPF does not create a new View each time I create a new ViewModel? Is there some way I can force WPF to discard the old view if the old viewmodel is destroyed?
<DataTemplate x:Shared="False" DataType="{x:Type VM:ResultsViewModel}">
<VW:ResultsView/>
</DataTemplate>
See Kent's answer for practical work-around for your issue.
That said, it's a good practice to only instantiate the View once, as there is overhead associated with constructing the Visual Tree and setting up all of the bindings. Generally the View/ViewModel should be designed so that you can swap out the underlying ViewModel without the View caring or even noticing (other than DataContext changing and therefore all binding values being re-evaluated.) If you currently have logic in your Loaded event that prepares for a specific ViewModel, consider registering for notification of when DataContext changes instead (see this example).

Silverlight MVVM question regarding views and viewmodels

I feel mysefl confused about how to implement view switching when view model changes. Example of what i'm tring to do:
The control I want to make is something like a wizard control. I have a list of view models added to collection of wizardsteps, and a current item viewmodel. How to display the view of active view model and switch them then active view model changes? How do I bind them?
In WPF I'd use DataTemplate but Silverlight doesn't support x:Type.
<DataTemplate DataType="{x:Type ViewModel1}">
<view:View1 />
</DataTemplate>
<DataTemplate DataType="{x:Type ViewModel2}">
<view:View2 />
</DataTemplate>
I think a wizard is a case where you should have one ViewModel for multiple Views.
You could control the visibility of each view with Properties (IsPage1Visible, IsPage2Visible,...), Commands (PreviowsPageCommand, NextPageCommand, CancelComamnd) and all logic in only one VM.
Put all "pages" of the wizard in one UserControl and bind the visilitiy of each with the boolean properties and a BooleanToVisibilityConverter.
Check this out, it talks about non-linear navigation in SL/WPF and how to maintain state. http://karlshifflett.wordpress.com/2010/07/07/non-linear-navigation-in-silverlight-4/

Resources