Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Change between pages in WPF

Tags:

c#

wpf

blend

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  pagesecond 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!

like image 485
ioan Avatar asked Jul 24 '14 11:07

ioan


3 Answers

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" />
like image 180
Sheridan Avatar answered Oct 06 '22 19:10

Sheridan


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!

like image 23
Immortal Blue Avatar answered Oct 06 '22 18:10

Immortal Blue


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.

like image 2
sobby01 Avatar answered Oct 06 '22 17:10

sobby01