|
|||||||||||||||||||||
|
|||||||||||||||||||||
|
Announcements
Services
Chapters
Feature Zones
|
IntroductionOne 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 WPFMy goal is to build a simple WPF application with three pages. Each of the pages should consist of three areas:
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.
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 <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 PageThe basis for my master page is a new custom control named
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. 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 In my case, I defined a style for my new class <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 Now our master page is ready to use. All we had to do was to:
Using the Master PageFinally we are able to build a new page based on the master page. Therefore we need a reference to the <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 <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
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 <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 ...
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
History
| ||||||||||||||||||||