简体   繁体   中英

Handling Navigation in MVVM WPF application

I am developing a WPF application that follows MVVM. Now I am handling navigation of views in the following manner. MainWindow View

<Border>
    <StackPanel>
    <local:Home
               Content="{Binding CurrentView,Converter={StaticResource ViewConverterHome}, UpdateSourceTrigger=PropertyChanged}"/>
    <local:Page1
            Content="{Binding CurrentView,Converter={StaticResource ViewConverterPage1}, UpdateSourceTrigger=PropertyChanged}"/>
    <local:Page2
        Content="{Binding CurrentView,Converter={StaticResource ViewConverterPage2}, UpdateSourceTrigger=PropertyChanged}"/>
    </StackPanel>

</Border>

Home, Page1,Page2 are 3 views. HomeVM,Page1VM,Page2VM are view models corresponding to the views. There is a class call ApplicationViewModel that contains a property CurrentView of type CViewModelBase which is the parent class for all three viewmodels. ApplicationViewModel handles the navigation in the folowing manner

   private void OnUserInputNextClicked(object sender, OperationInformationChangedEventArgs e)
    {
        do
        {
            if (this.CurrentView is HomeVM)
            {
                this.CurrentView = null;
                Page1VM page1 = new Page1VM("BNM", "MATH HONS", "13");
                page1.NextCilcked += new EventHandler<OperationInformationChangedEventArgs>(OnUserInputNextClicked);
                page1.BackCilcked += new EventHandler<OperationInformationChangedEventArgs>(OnUserInputBackClicked);
                this.CurrentView = page1;
                break;
            }

            if (this.CurrentView is Page1VM)
            {
                this.CurrentView = null;
                Page2VM page2 = new Page2VM("Kolkata", "Monoj", "Itachuna");
                page2.NextCilcked += new EventHandler<OperationInformationChangedEventArgs>(OnUserInputNextClicked);
                page2.BackCilcked += new EventHandler<OperationInformationChangedEventArgs>(OnUserInputBackClicked);
                this.CurrentView = page2;
                break;
            }
            if (this.CurrentView is Page2VM)
            {
                this.CurrentView = null;
                HomeVM home = new HomeVM("Anirban", "30");
                home.NextCilcked += new EventHandler<OperationInformationChangedEventArgs>(OnUserInputNextClicked);
                this.CurrentView = home;
                break;
            }
        } while (false);
    }

The navigation is working perfectly; But dispose of disappeared views are not getting called.So all the views live till the end. Is there any way to prevent that?

Your Views will always exist because you added a copy of each one to your UI with the XAML, even if the Content contained in them may not exist

Typically I will use a ContentControl to display content instead of creating an instance of the control for each content type, and I'll use DataTemplates to tell WPF how to draw each type of content.

For example,

<Window.Resources>
    <DataTemplate DataType="{x:Type local:HomeVM}">
        <local:Home Content="{Binding }" />
    </DataTemplate>
    <DataTemplate DataType="{x:Type local:Page1VM}">
        <local:Page1 Content="{Binding }" />
    </DataTemplate>
    <DataTemplate DataType="{x:Type local:Page2VM}">
        <local:Page2 Content="{Binding }" />
    </DataTemplate>
</Window.Resources>

<Border>
    <StackPanel>
        <ContentControl Content="{Binding CurrentView}" />
    </StackPanel>
</Border>

This way, you only have one instance of your Content in the VisualTree, and the DataTemplate WPF users to draw your content changes based on it's DataType .

I have an example of this kind of navigation with WPF on my blog if you're interested in checking out a full code sample

You need to change DataContext of MainWindow. It depends on your integration. When I make a MVVM application what I do is that pass MainWindow object to every view constructor. And whenever I have to move to next page (like on next button) I change the MainWindow object DataContext to new view.

Something like this.

public PageOneViewModel
{

    private MainWindow _mainWindow;
    public PageOneViewModel(MainWindow mainWindow)
    {
         // Here I am saving MainWindow object.
         _mainWindow = mainWindow;
    }

    public OnNext()
    {
         // Here I am changing the view.
         MainWindow.DataContext = new PageTwoViewModel(_mainWindow);
    }
}

Have you considered using Frame?

<Frame Name="YourFrame" Navigated="OnNavigated"/>

and then you can call

YourFrame.CanGoBack(), YourFrame.GoBack()

etc.

Here's a link to my answer to a similar question with working source code. The technique I used is a little similar to Faisal's solution.

If you need a good downloadable sample solution that demonstrates navigation using a side menu, look at here and here(simpler example) .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM