Click here to Skip to main content
15,867,704 members
Articles / Desktop Programming / WPF
Article

WPF Master Pages

Rate me:
Please Sign up or sign in to vote.
4.83/5 (49 votes)
21 Jan 2008CPOL4 min read 354.3K   7K   99   48
One of the really great enhancements in ASP.NET was the introduction of master pages. They help developers to create a consistent layout for the pages in an application. Unfortunately there is no such concept in WPF. But there is an easy way to build a control similar to an ASP.NET master page.

Introduction

One of the really great enhancements in ASP.NET was the introduction of master pages. They help developers to create a consistent layout for the pages in an application. Unfortunately, there is no such concept in WPF and XAML. In the following sample, I would like to show a simple way to build a control in WPF similar to an ASP.NET master page.

Layout in WPF

My goal is to build a simple WPF application with three pages. Each of the pages should consist of three areas:

  1. A title
  2. An abstract
  3. The main content

The screenshot shows the first page of the application. In this case, all three areas contain some text. But as we will see later in the sample, we are not limited to text.

Image 1

If I would build this page without using a master page, I would start with a new blank page and then I would arrange different types of controls on this page. I used Stackpanels and a Grid to arrange the logo and the three types of content on the page.

XML
<Page x:Class="MasterPages.Page.PageWithoutMaster"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  Title="PageWithoutMaster">
  <Page.Resources>
    <ResourceDictionary>
      <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary Source="../Style/Logo.xaml" />
        <ResourceDictionary Source="../Style/Standard.xaml" />
      </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
  </Page.Resources>
  
  <StackPanel>
    <Grid Height="70">
      <Image Source="{StaticResource SoftwareArchitectsLogoBackground}"
        Stretch="Fill" />
      <Grid Margin="10">
        <Image Source="{StaticResource SoftwareArchitectsLogo}" 
          HorizontalAlignment="Left" />
      </Grid>
    </Grid>
    <StackPanel Margin="10">
      <TextBlock Style="{StaticResource Title}">
        About us
      </TextBlock>
      <TextBlock Style="{StaticResource Abstract}">
        software architects builds a ...
      </TextBlock>
      <TextBlock>
        In the long term software architects ...
      </TextBlock>
    </StackPanel>
  </StackPanel>
</Page>

This works very well for one single page, but when adding new pages I have to care about including the general layout code consistently. And it really gets bad when I would like to change the layout after building lots of pages. To avoid this problem, I would like to have something similar to ASP.NET master pages in my WPF projects.

Building a Master Page

The basis for my master page is a new custom control named Master in my project. I added three dependency properties:

  1. Title
  2. Abstract
  3. Content

Each property represents one area in my master page. The datatype for the dependency properties is object. This ensures that I cannot only add text but also controls to each area in the page.

C#
namespace MasterPages.Master
{
  public class Master : Control
  {
    static Master()
    {
      DefaultStyleKeyProperty.OverrideMetadata(typeof(Master), 
        new FrameworkPropertyMetadata(typeof(Master)));
    }

    public object Title
    {
      get { return (object)GetValue(TitleProperty); }
      set { SetValue(TitleProperty, value); }
    }

    public static readonly DependencyProperty TitleProperty =
      DependencyProperty.Register("Title", typeof(object), 
      typeof(Master), new UIPropertyMetadata());

    public object Abstract
    {
      get { return (object)GetValue(AbstractProperty); }
      set { SetValue(AbstractProperty, value); }
    }

    public static readonly DependencyProperty AbstractProperty =
      DependencyProperty.Register("Abstract", typeof(object), 
      typeof(Master), new UIPropertyMetadata());

    public object Content
    {
      get { return (object)GetValue(ContentProperty); }
      set { SetValue(ContentProperty, value); }
    }

    public static readonly DependencyProperty ContentProperty =
      DependencyProperty.Register("Content", typeof(object), 
      typeof(Master), new UIPropertyMetadata());
  }
}

As you may know, WPF does not add layout information into the class implementing a custom control like Master. The content of the file generic.xaml defines the look of the control. This file is automatically created by Visual Studio as soon as you add a custom control to your project.

In my case, I defined a style for my new class Master in generic.xaml. This is the place where the arrangement of the areas should happen. Just as in the single page before I used Stackpanels and Grids to arrange the logo and all the other parts of the page. The key to include the content of the dependency properties is the control ContentPresenter. I inserted three of them and bound them to the three dependency properties of the Master class.

XML
<ResourceDictionary
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:local="clr-namespace:MasterPages.Master">

  <ResourceDictionary.MergedDictionaries>
    <ResourceDictionary Source="Style/Logo.xaml" />
    <ResourceDictionary Source="Style/Master.xaml" />
  </ResourceDictionary.MergedDictionaries>

  <Style TargetType="{x:Type local:Master}">
    <Setter Property="Template">
      <Setter.Value>
        <ControlTemplate TargetType="{x:Type local:Master}">
          <StackPanel>
            <Grid Height="70">
              <Image 
                Source="{StaticResource SoftwareArchitectsLogoBackground}"
                Stretch="Fill" />
              <Grid Margin="10">
                <Image Source="{StaticResource SoftwareArchitectsLogo}" 
                  HorizontalAlignment="Left" />
              </Grid>
            </Grid>
            <StackPanel Margin="10">
              <ContentPresenter Content="{TemplateBinding Title}" 
                Style="{StaticResource Title}" />
              <ContentPresenter Content="{TemplateBinding Abstract}" 
                Style="{StaticResource Abstract}" />
              <ContentPresenter Content="{TemplateBinding Content}" />
            </StackPanel>
          </StackPanel>
        </ControlTemplate>
      </Setter.Value>
    </Setter>
  </Style>
</ResourceDictionary>

I added some ResourceDictionary objects to the generic.xaml for my more complex styles like the logo, which is entirely built in XAML.

Now our master page is ready to use. All we had to do was to:

  • Insert a new custom control
  • Add a dependency property for each area of the page
  • Define the layout of the control in the file generic.xaml

Using the Master Page

Finally we are able to build a new page based on the master page. Therefore we need a reference to the Master class in our WPF file: xmlns:m="clr-namespace:MasterPages.Master". I chose the prefix m for my Master class. With this prefix, I can add a new instance of Master to the page. Inside of <m:Master> I can set the Title, the Abstract and the Content property of the class.

XML
<Page x:Class="MasterPages.Page.Page1"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:m="clr-namespace:MasterPages.Master"
  Title="Page1">
  <m:Master>
    <m:Master.Title>
      About us
    </m:Master.Title>
    <m:Master.Abstract>
      software architects builds a new generation of ...
    </m:Master.Abstract>
    <m:Master.Content>
      In the long term software architects will offer ...
    </m:Master.Content>
  </m:Master>
</Page>

In this case, I only used text but as you can see in the next sample I am not limited to text.

To show the advantage of a master page, I added a second page to my project. Again I do not have to care about layout any more. I just add the Master control to my page and set the properties of the control. But this time, I add more advanced content to the control. The Content property holds a StackPanel with a ListBox.

XML
<Page x:Class="MasterPages.Page.Page2"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:m="clr-namespace:MasterPages.Master"
  Title="Page2">
  <m:Master>
    <m:Master.Title>
      Page 2
    </m:Master.Title>
    <m:Master.Abstract>
      Page 2 contains a ListBox.
    </m:Master.Abstract>
    <m:Master.Content>
      <StackPanel>
        <ListBox>
          <ListBoxItem>Item 1</ListBoxItem>
          <ListBoxItem>Item 2</ListBoxItem>
          <ListBoxItem>Item 3</ListBoxItem>
        </ListBox>
      </StackPanel>
    </m:Master.Content>
  </m:Master>
</Page>

As you can see in the following screenshot, my second page looks similar to my first one. Instead of the text, it shows a ListBox with some items.

Image 2

If you want to access controls of your page in the codebehind file, you just have to add a name to the control. In the following sample, I added a Button to the Content area of my page:

XML
 <Page x:Class="MasterPages.Page.Page3"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:m="clr-namespace:MasterPages.Master"
  Title="Page3">
  <m:Master>
    <m:Master.Title>
      Page 3
    </m:Master.Title>
    <m:Master.Abstract>
      Page 3 contains a Button, which opens a MessageBox.
    </m:Master.Abstract>
    <m:Master.Content>
      <StackPanel>
        <Button Name="btnShowMessage" Content="Show MessageBox" />
      </StackPanel>
    </m:Master.Content>
  </m:Master>
</Page>

In the codebehind file of the page, I added a click eventhandler to the button which shows a messagebox when it is clicked.

C#
...

protected override void OnInitialized(EventArgs e)
{
  base.OnInitialized(e);
  btnShowMessage.Click += new RoutedEventHandler(BtnShowMessage_Click);
}

private void BtnShowMessage_Click(object sender, RoutedEventArgs e)
{
  MessageBox.Show("You clicked the button.");
}

...

Again, I do not have to worry about the layout of the page. The logo, the background, the colors and everything else that makes up a page in my project are encapsulated in the Master class. I just have to care about the things that are unique to my page like the button and its eventhandler.

Page3.png

History

  • 21st January, 2008: Initial post

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer software architects
Austria Austria
Hi, my name is Karin Huber. Since 1998 I have been working as a developer and IT consultant focusing on building database oriented web applications. In 2007 my friend Rainer and I decided that we want to build a business based on COTS (component off-the-shelf) software. As a result we founded "software architects".

These days we are offering our first version of the time tracking software called 'time cockpit'. You can find more information at www.timecockpit.com.

Comments and Discussions

 
GeneralMy vote of 5 Pin
Keenan Stewart 202228-Oct-22 2:39
Keenan Stewart 202228-Oct-22 2:39 
GeneralNicely crafted! Pin
Chamadness28-Apr-14 21:23
Chamadness28-Apr-14 21:23 
Questionhow to Navigation Between 3 pages like page1 page2 Pin
LakDinesh30-Jan-14 18:40
professionalLakDinesh30-Jan-14 18:40 
QuestionAccessing properties Pin
Lucedoriente19-Sep-13 4:29
Lucedoriente19-Sep-13 4:29 
GeneralMy vote of 4 Pin
eswar_kanchu3-Jul-13 7:30
eswar_kanchu3-Jul-13 7:30 
QuestionVery nice Pin
BillW3326-Mar-13 5:58
professionalBillW3326-Mar-13 5:58 
QuestionThank you! Pin
Gianluca Palmieri19-Nov-12 11:05
Gianluca Palmieri19-Nov-12 11:05 
QuestionGood Pin
yangshaokai22-Apr-12 15:49
yangshaokai22-Apr-12 15:49 
GeneralMy vote of 5 Pin
mojmos19-Oct-11 23:36
mojmos19-Oct-11 23:36 
GeneralMy vote of 5 Pin
Stiaan Jacobs9-Oct-11 20:49
Stiaan Jacobs9-Oct-11 20:49 
GeneralMy vote of 5 Pin
Member 805109012-Aug-11 3:41
Member 805109012-Aug-11 3:41 
QuestionSet Content From Content Page Pin
Talabér Ferenc22-Mar-11 2:13
Talabér Ferenc22-Mar-11 2:13 
GeneralMy vote of 5 Pin
mzworowski28-Sep-10 16:59
mzworowski28-Sep-10 16:59 
GeneralProblem using LINQ inside Content Page Pin
Dani Boi28-Sep-09 22:21
Dani Boi28-Sep-09 22:21 
GeneralShe tight Pin
Dani Boi16-Sep-09 1:53
Dani Boi16-Sep-09 1:53 
GeneralWOW TALK ABOUT PURE BEAUT IN A LADY Pin
stecevsrf3-Aug-09 11:35
stecevsrf3-Aug-09 11:35 
GeneralLosing all design from master window Pin
Ashish Sehajpal5-Jan-09 0:55
Ashish Sehajpal5-Jan-09 0:55 
QuestionExtracting Master.cs into a separate assembly Pin
Ryan Riley18-Jun-08 4:08
Ryan Riley18-Jun-08 4:08 
GeneralGreat Article! Pin
Kavan Shaban18-Apr-08 18:52
Kavan Shaban18-Apr-08 18:52 
GeneralFurther details on the fix Pin
Member 267213525-Feb-08 5:09
Member 267213525-Feb-08 5:09 
GeneralRe: Further details on the fix Pin
Member 798776229-Apr-14 2:49
Member 798776229-Apr-14 2:49 
GeneralFix For Control: Derive from ContentControl instead of Control Pin
User 27100919-Feb-08 2:19
User 27100919-Feb-08 2:19 
GeneralRe: Fix For Control: Derive from ContentControl instead of Control Pin
Member 267213522-Feb-08 12:16
Member 267213522-Feb-08 12:16 
QuestionBinding to a property of a control inside master page [modified] Pin
Eshva19-Feb-08 1:06
Eshva19-Feb-08 1:06 
GeneralRe: Binding to a property of a control inside master page Pin
User 27100919-Feb-08 2:10
User 27100919-Feb-08 2:10 
I did verify that their code does not work if you bind inside it. I went to Page2.xaml and added in the two TextBlocks and the Binding gave the same error.

Try using Snoop or Mole to see what is going on inside.

You can just rewrite their approach to make it work.

I have never seen this problem with my own code.

Maybe Karin can address this issue also.

Cheers, Karl

My Blog | Mole's Home Page | How To Create Screen Capture Videos For Your Articles

Just a grain of sand on the worlds beaches.




modified 27-Feb-21 21:01pm.

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.