Change between pages in WPF

34,776

Solution 1

If you are going to use Pages in WPF, then you will need to read the Navigation Overview page on MSDN. In short however, you can navigate between Pages in a WPF Application by using the NavigationService Class. To change the page from code behind, you could do something like this:

NextPage page = new NextPage();
NavigationService.Navigate(page);

To let the users change the Page, you can use the Hyperlink Class in your Pages:

<Hyperlink NavigateUri="pack://application:,,,/AppName;component/Pages/NextPage.xaml">
    Navigate to Next Page
</Hyperlink>

To get your desired page setup, you will have to load your Pages into a Frame, which you can then layout wherever you like in MainWindow.xaml:

<Frame Source="pack://application:,,,/AppName;component/Pages/SomePage.xaml" />

Solution 2

Sounds like you need a custom usercontrol and some databinding.

You can declare DataTemplates in XAML as resources with the model type as key, so that WPF chooses the correct DataTemplate automatically:

  • Have a main ViewModel, which exposes a ImageSourceViewModel property. This property would either return a CameraSourceViewModel or a FileSourceViewModel, as appropriate.

  • In your page, the DataContext would be the main ViewModel, and you'd have XAML like this:

Then,

<Page x:Class="Page1"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
  xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
  xmlns:my="clr-namespace:WpfApplication1"
  mc:Ignorable="d" 
  d:DesignHeight="300" d:DesignWidth="300"
  Title="Page1">
<Page.Resources>
    <DataTemplate DataType="{x:Type my:CameraSourceViewModel}">
        <my:CameraSourceView/>
    </DataTemplate>
    <DataTemplate DataType="{x:Type my:FileSourceViewModel}">
        <my:FileSourceView/>
    </DataTemplate>
</Page.Resources>
<Grid>
    <ContentControl Content="{Binding ImageSourceViewModel}"/>
</Grid>

I should point out that this example uses the MVVM pattern to allow the viewmodel layer to decide on the content in the middle. Hopefully this is clear enough, if not, give me a shout and I'll try to expand it!

Solution 3

Let's say I have main view model where I've created a CurrentPage property that will tell which page you want to display.

/// <summary>
/// Returns the page ViewModel that the user is currently viewing.
/// </summary>
public ViewModelBase CurrentPage
{
    get { return _currentPage; }
    private set
    {
        if (value != _currentPage)
        {
            if (_currentPage != null)
                _currentPage.IsCurrentPage = false;

            _currentPage = value;

            if (_currentPage != null)
                _currentPage.IsCurrentPage = true;
            RaisePropertyChanged(() => CurrentPage);
        }
    }
}

And in your xaml you can bind your page under some control. Let's say I am doing it inside a Border element.

<!-- CURRENT PAGE AREA -->
<Border Background="White" Grid.Column="1" Grid.Row="0">
    <HeaderedContentControl Content="{Binding Path=CurrentPage}" 
        Header="{Binding Path=CurrentPage.DisplayName}" />
</Border>

You can define view to your view model in resources just like this:
(partially complete XAML)

<UserControl x:Class="BAT.View.BATWizardView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:view="clr-namespace:BAT.View"
        xmlns:viewmodel="clr-namespace:BAT.ViewModel"
        mc:Ignorable="d" 
        d:DesignHeight="350" d:DesignWidth="600">

   <UserControl.Resources>
      <!-- These four templates map a ViewModel to a View. -->
      <DataTemplate DataType="{x:Type viewmodel:MyComparisonViewModel1}">
          <view:MyView1 />
      </DataTemplate>

      <DataTemplate DataType="{x:Type viewmodel:MyComparisonViewModel2}">
          <view:MyView2 />
      </DataTemplate>

   </UserControl.Resources>
   <Grid>
      <Border Background="White" Grid.Column="1" Grid.Row="0">
         <HeaderedContentControl Content="{Binding Path=CurrentPage}" 
                      Header="{Binding Path=CurrentPage.DisplayName}" />
      </Border>
   </Grid>
</UserControl>

See if that helps.

Share:
34,776
ioan
Author by

ioan

Software Developer based in London

Updated on October 01, 2020

Comments

  • ioan
    ioan over 3 years

    I want to make a layout like the one used in any website - the header, sidebar and footer stay the same but the center part. I have multiple pages/windows to show in a wpf blend C# application and they are totally different. For example, stackoverflow has a layout for the homepage and another one for each Question. Here's another exemple:

    first  page second page

    I had to do that in a previous project and I used a single grid layout and then, for each page, I had to hide() all of them and show that each one on top -

    What's the trick? How can I do the same thing in a wpf application? In a typical C# application I would have to open a child window each time but that seems ugly these days.

    Thank you in advance!

  • Marcus Mangelsdorf
    Marcus Mangelsdorf over 8 years
    The Navigation Overview MSDN page for .NET Framework 4.5 seems to be removed/broken, but you can still find the .NET Framework 4.0 version here.
  • Sheridan
    Sheridan over 8 years
    Many thanks @Merlin2001... I've updated the link now.