Click here to Skip to main content
11,648,960 members (83,532 online)
Click here to Skip to main content

Creating an Outlook Navigation Pane by Restyling a WPF TabControl

, 24 Jun 2008 CPOL 191.7K 6.7K 187
Rate this:
Please Sign up or sign in to vote.
Restyling a standard TabControl to look like an Outlook Navigation Pane


Arguable Office 2007 has revolutionized the way modern user interfaces will look like with great innovations like the ribbon... The control I would like to focus on in this article though is the Office 2007 Navigation Pane, or more specifically, how to recreate the Navigation Pane by restyling a TabControl!

The WPF team has done an excellent job of reducing the need to create custom controls by allowing "lookless controls" to be re-styled! This is how the Navigation Pane looks:


And this is how our standard TabControlcurrently looks:


Here is the XAML:

<TabControl VerticalAlignment="Stretch" Width="360" Height="Auto"
    <TabItem Header="Mail">
    <TabItem Header="Calendar">
    <TabItem Header="Contacts">
    <TabItem Header="Tasks">

Before I begin restyling, to keep the beginner status for my article, I will briefly explain what a Style and Template are and how they are used here!

What is a Style?

A Style's main function is to group together property values that could otherwise be set individually. The intent is to then share this group of values among multiple elements. If you look at a simple Style in XAML, you will notice that generally it has a TargetType set and then a collection of Setters. Each Setterthen allows you to replace a given Propertyvalue with the provided value. Here is a very basic example:

<Style x:Key="SimpleStyle" TargetType="{x:Type TabControl}">
    <Setter Property="Foreground" Value="Blue" />
    <Setter Property="Background" Value="Yellow" />

While this is the standard definition of a Style, in this restyle article, it is more used to just replace the Templateproperty.

What is a Template?

A Templateallows you to completely replace an element’s visual tree with anything you can dream up, while keeping all of its functionality intact. Here is an example of how we use a style/setterto replace a Template.

<Style x:Key="SimpleStyle" TargetType="{x:Type TabControl}">
    <Setter Property="Template">
            <ControlTemplate TargetType="{x:Type TabControl}">
                <!--<span class="code-comment"> The new visual tree should be placed here --></span>

Since the Templateis just a property on the Controlobject (from which TabControlderives), it can also be replaced by using a setter! We can now replace the complete visual tree while keeping the basic functionality of a TabControl!

For more information about deriving from Control, have a look here.

Restyling the TabControl

The TabControluses a TabPanelto layout the TabControl's tabs (or buttons). We will now replace this with a StackPanel:

<Style x:Key="OutlookTabControlStyle" TargetType="{x:Type TabControl}">
    <Setter Property="Foreground"
        Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
    <Setter Property="Background"
        Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
    <Setter Property="BorderBrush" Value=
      "{x:Static Microsoft_Windows_Themes:ClassicBorderDecorator.ClassicBorderBrush}"/>
    <Setter Property="BorderThickness" Value="3"/>
    <Setter Property="Margin" Value="0"/>
    <Setter Property="Padding" Value="1"/>
    <Setter Property="MinWidth" Value="10"/>
    <Setter Property="MinHeight" Value="10"/>
    <Setter Property="HorizontalContentAlignment" Value="Center"/>
    <Setter Property="VerticalContentAlignment" Value="Center"/>
    <Setter Property="Template">
            <ControlTemplate TargetType="{x:Type TabControl}">
                <Grid ClipToBounds="true" SnapsToDevicePixels="true"
                        <RowDefinition x:Name="RowDefinition0" Height="Auto"/>
                        <RowDefinition x:Name="RowDefinition1" Height="*"/>
                        <ColumnDefinition x:Name="ColumnDefinition0"/>
                        <ColumnDefinition x:Name="ColumnDefinition1" Width="0"/>
                    <Grid x:Name="ContentPanel" Grid.Column="0" Grid.Row="1"
                        Background="{TemplateBinding Background}"
                        BorderBrush="{TemplateBinding BorderBrush}"
                        BorderThickness="{TemplateBinding BorderThickness}">
                            <ContentPresenter SnapsToDevicePixels=
                            "{TemplateBinding SnapsToDevicePixels}" Margin="2,2,2,2"
                    <StackPanel HorizontalAlignment="Stretch" Margin="0,-2,0,0"
                    x:Name="HeaderPanel" VerticalAlignment="Bottom" Width="Auto" 
                Height="Auto" Grid.Row="1" IsItemsHost="True"/>
                    <Trigger Property="TabStripPlacement" Value="Bottom">
                        <Setter Property="Grid.Row"
                        TargetName="ContentPanel" Value="0"/>
                        <Setter Property="Height"
                            TargetName="RowDefinition0" Value="*"/>
                        <Setter Property="Height"
                            TargetName="RowDefinition1" Value="Auto"/>
                    <Trigger Property="TabStripPlacement" Value="Left">
                        <Setter Property="Grid.Row"
                            TargetName="ContentPanel" Value="0"/>
                        <Setter Property="Grid.Column"
                            TargetName="ContentPanel" Value="1"/>
                        <Setter Property="Width"
                            TargetName="ColumnDefinition0" Value="Auto"/>
                        <Setter Property="Width"
                            TargetName="ColumnDefinition1" Value="*"/>
                        <Setter Property="Height"
                            TargetName="RowDefinition0" Value="*"/>
                        <Setter Property="Height"
                            TargetName="RowDefinition1" Value="0"/>
                    <Trigger Property="TabStripPlacement" Value="Right">
                        <Setter Property="Grid.Row"
                            TargetName="ContentPanel" Value="0"/>
                        <Setter Property="Grid.Column"
                            TargetName="ContentPanel" Value="0"/>
                        <Setter Property="Width"
                            TargetName="ColumnDefinition0" Value="*"/>
                        <Setter Property="Width"
                            TargetName="ColumnDefinition1" Value="Auto"/>
                        <Setter Property="Height"
                            TargetName="RowDefinition0" Value="*"/>
                        <Setter Property="Height"
                            TargetName="RowDefinition1" Value="0"/>
                    <Trigger Property="IsEnabled" Value="false">
                        <Setter Property="Foreground"
                            {x:Static SystemColors.GrayTextBrushKey}}"/>

All of this is automatically created by blend by right-clicking on the TabControland selecting "Edit Control Parts (Template)" -> "Edit a Copy..."


Next, in XAML just replace the TabPanelwith the StackPanel. The only important property to set on the StackPanelis the IsItemsHost="true".


After replacing the TabPanelwith a StackPanel, set each TabItemsheight to 30, the TabControl's Backgroundto Whiteand the BorderBrushto #FF6593CF.


Well, this looks better...

What are Resources?

Resources or more specifically, ResourceDictionaryis just a dictionary of key/value pairs that can be accessed from XAML. It is used here to define brushes that are commonly used. Here is a simple example:

<SolidColorBrush x:Key="OutlookButtonForeground" Color="#FF204D89"/>

and here a use for it:

Foreground="{DynamicResource OutlookButtonForeground}"

Restyling the TabItem

Next, create a style for a TabItemby right-clicking on one of them and selecting "Edit Control Parts (Template)" -> "Edit a Copy..."

Before I dig into the default style created, I just want to create two brush resources. The first brush resource is the normal color of a Navigation Pane button:

<LinearGradientBrush x:Key="OutlookButtonBackground" EndPoint="0.5,1" StartPoint="0.5,0">
    <GradientStop Color="#FFD9EDFF" Offset="0"/>
    <GradientStop Color="#FFC0DEFF" Offset="0.445"/>
    <GradientStop Color="#FFC0D9GB" Offset="1"/>
    <GradientStop Color="#FFAFD1F8" Offset="0.53"/>

And the next is the default text color of a button:

<SolidColorBrush x:Key="OutlookButtonForeground" Color="#FF204D89"/>

So, each TabItemshould now look something like this:

<TabItem Header="Tasks" Height="30" Style="{DynamicResource OutlookTabItemStyle}"
    Background="{DynamicResource OutlookButtonBackground}"
            Foreground="{an>DynamicResource OutlookButtonForeground}">

Creating a stylefor the TabItemhas two purposes: Align the TabItem's header to the left and change the TabItem's border from a ClassicBorder to a normal Border (for more control).

<Style x:Key="OutlookTabItemStyle" TargetType="{x:Type TabItem}">
    <Setter Property="FocusVisualStyle" Value="{StaticResource TabItemFocusVisual}"/>
    <Setter Property="Padding" Value="12,2,12,2"/>
    <Setter Property="Foreground"
        Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
    <Setter Property="Background"
        Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
    <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
    <Setter Property="VerticalContentAlignment" Value="Stretch"/>
    <Setter Property="Template">
            <ControlTemplate TargetType="{x:Type TabItem}">
                <Border SnapsToDevicePixels="true" x:Name="Bd"
                    Background="{TemplateBinding Background}"
                    BorderThickness="1" BorderBrush="#FF6593CF">
                    <ContentPresenter SnapsToDevicePixels=
                        "{TemplateBinding SnapsToDevicePixels}"
                        Margin="{TemplateBinding Padding}"
                VerticalAlignment="{Binding Path=VerticalContentAlignment,
                RelativeSource={RelativeSource AncestorType=
                        {x:Type ItemsControl}}}"
                ContentSource="Header" RecognizesAccessKey="True"

This is how it looks now: "BetterStyle.jpg"


Ahhh... even better! So, what's next?

What are Triggers?

Triggershave a collection of Setters just like Style(and/or collections of TriggerActions). But whereas a Styleapplies its values unconditionally, a triggerperforms its work based on one or more conditions. There are three types of triggers:

  • Property triggers— Invoked when the value of a dependency property changes
  • Data triggers— Invoked when the value of a plain .NET property changes
  • Event triggers— Invoked when a routed event is raised

We will make use of an Event Trigger. The TabItemprovides us with an IsSelectedrouted event!


We now need to indicate (by changing color) that an item is selected. Again, we create a brush to represent the color the button needs to change to once highlighted:

<LinearGradientBrush x:Key="OutlookButtonHighlight" EndPoint="0.5,1" StartPoint="0.5,0">
    <GradientStop Color="#FFFFBD69" Offset="0"/>
    <GradientStop Color="#FFFFB75A" Offset="0.0967"/>
    <GradientStop Color="#FFFFB14C" Offset="0.2580"/>
    <GradientStop Color="#FFFB8C3C" Offset="0.3870"/>
    <GradientStop Color="#FFFEB461" Offset="0.9677"/>
    <GradientStop Color="#FFFEBB67" Offset="1"/>

And here is the trigger:

    <Trigger Property="Selector.IsSelected" Value="True">
        <Setter Property="Background" TargetName="Bd"
                Value="{DynamicResource OutlookButtonHighlight}"/>

Here is how it looks:


That's better...

That is basically all that is required to restyle a TabControl!


  • 4th March, 2008 - Initial release
  • 5th March, 2008 - Changed the title, updated the colors
  • 23rd June, 2008 - Added source file

Please vote for this article if you liked it and also visit my blog.
Thank you!


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


About the Author

South Africa South Africa
No Biography provided

You may also be interested in...

Comments and Discussions

GeneralSilverlight Pin
spook30-Sep-09 16:38
memberspook30-Sep-09 16:38 
GeneralRe: Silverlight Pin
rudigrobler30-May-10 2:02
memberrudigrobler30-May-10 2:02 
GeneralRe: Silverlight Pin
JiltedCitizen15-Jul-10 7:45
memberJiltedCitizen15-Jul-10 7:45 
GeneralTemplate problem Pin
MrPMorris9-Jul-09 4:10
memberMrPMorris9-Jul-09 4:10 
Generalgood Pin
zhujinlong1984091316-Apr-09 20:45
groupzhujinlong1984091316-Apr-09 20:45 
QuestionHow can i add picture and events.. Pin
fifiza10-Mar-09 2:46
memberfifiza10-Mar-09 2:46 
Questionhow can i provide shrink functonality in this control Pin
Om S Pathak15-Dec-08 4:02
memberOm S Pathak15-Dec-08 4:02 
GeneralNice Job... Pin
Castle Rider16-Nov-08 18:16
memberCastle Rider16-Nov-08 18:16 
QuestionAbout the Images/Icons Pin
dearcyrix12-Oct-08 18:20
memberdearcyrix12-Oct-08 18:20 
QuestionTabStripPlacement - does it work? Pin
Indy200526-Jun-08 18:07
memberIndy200526-Jun-08 18:07 
AnswerRe: TabStripPlacement - does it work? Pin
rudigrobler26-Jun-08 20:10
memberrudigrobler26-Jun-08 20:10 
GeneralRe: TabStripPlacement - does it work? Pin
holy_spirit18-Jan-09 23:43
memberholy_spirit18-Jan-09 23:43 
AnswerRe: TabStripPlacement - does it work? Pin
holy_spirit19-Jan-09 1:19
memberholy_spirit19-Jan-09 1:19 
QuestionPlease help me Pin
Member 268137218-Jun-08 22:32
memberMember 268137218-Jun-08 22:32 
AnswerRe: Please help me Pin
rudigrobler22-Jun-08 23:51
memberrudigrobler22-Jun-08 23:51 
GeneralGood one Pin
pgr200616-May-08 2:16
memberpgr200616-May-08 2:16 
GeneralRe: Good one Pin
rudigrobler22-Jun-08 23:53
memberrudigrobler22-Jun-08 23:53 
GeneralNice Job! Pin
BOTs - running in my mind 26-Mar-08 19:52
member BOTs - running in my mind 26-Mar-08 19:52 
GeneralRe: Nice Job! Pin
rudigrobler22-Jun-08 23:54
memberrudigrobler22-Jun-08 23:54 
GeneralNeato Pin
Sacha Barber6-Mar-08 8:59
mvpSacha Barber6-Mar-08 8:59 
GeneralRe: Neato Pin
rudigrobler6-Mar-08 19:42
memberrudigrobler6-Mar-08 19:42 
GeneralOutlook brushes Pin
Benoît Dion6-Mar-08 0:21
memberBenoît Dion6-Mar-08 0:21 
GeneralNice Pin
Yogesh Jagota5-Mar-08 18:35
memberYogesh Jagota5-Mar-08 18:35 
A much advanced example from Microsoft allows to make a exact replica of a Outlook UI. Although I cannot find the example on the msdn site anymore, but I have the source code. The example was called Outlook UI HOL.

This link lead me to the example, but does not work anymore, although the blog entry still exists:[^]
GeneralRe: Nice Pin
Angelo Cresta5-Mar-08 23:35
memberAngelo Cresta5-Mar-08 23:35 
GeneralBlend or VS2008 Pin
izwaldschwartz5-Mar-08 3:10
memberizwaldschwartz5-Mar-08 3:10 

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

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

| Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.150804.4 | Last Updated 24 Jun 2008
Article Copyright 2008 by rudigrobler
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid