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:
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!
If you are going to use Page
s in WPF, then you will need to read the Navigation Overview page on MSDN. In short however, you can navigate between Page
s 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 Page
s:
<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 Page
s into a Frame
, which you can then layout wherever you like in MainWindow.xaml
:
<Frame Source="pack://application:,,,/AppName;component/Pages/SomePage.xaml" />
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!
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With