When it comes to the WinForm's Tab Control, there was a lot left to be
desired. If you had to make major changes to either looks or
functionality, you were better off just writing your own tab control
completely from scratch. The WPF Tab Control makes major strides in the
right direction, and because of the power of WPF styles and control
templates, you pretty much have complete control over how the tab
control looks and feels. This tutorial is going to introduce you to the
tab control and demonstrate how to re-skin it look like how you want.
Let's start off easy by simply putting a regular old tab control in a
window and adding a couple of tabs.
<Window x:Class="TabControlTutorial.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="WPF Tabs" Height="281" Width="454">
<Grid>
<TabControl>
<TabItem Header="Cheese">
The Cheese Tab
</TabItem>
<TabItem Header="Pepperoni">
The Pepperoni Tab
</TabItem>
<TabItem Header="Mushrooms">
The Mushrooms Tab
</TabItem>
</TabControl>
</Grid>
</Window>
The above code gives you a pretty standard looking tab control like the
one pictured below.
Like most other WPF controls, the contents of a
TabItem
can be most any other WPF control. Let's look at a tab with an image set
as the content.<Window x:Class="TabControlTutorial.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="WPF Tabs" Height="281" Width="454">
<Grid>
<TabControl>
<TabItem Header="Cheese">
The Cheese Tab
</TabItem>
<TabItem Header="Pepperoni">
<Image Source="pepperoni.jpg" />
</TabItem>
<TabItem Header="Mushrooms">
The Mushrooms Tab
</TabItem>
</TabControl>
</Grid>
</Window>
That should look something like the following:
That's enough of the simple stuff. If all you want is a basic tab
control with some content on each tab, the above code will do everything
you need. Let's look at some more interesting stuff now. Just like the
content of the TabItem, the Header property of the TabItem can also have
other WPF controls. Let's put an image in each of the tabs.
<Window x:Class="TabControlTutorial.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="WPF Tabs" Height="281" Width="454">
<Grid>
<TabControl>
<TabItem>
<TabItem.Header>
<StackPanel Orientation="Horizontal">
<Image Height="18" Source="cheese.jpg" />
<TextBlock Text="Cheese" Margin="2,0,0,0" VerticalAlignment="Center" />
</StackPanel>
</TabItem.Header>
</TabItem>
<TabItem>
<TabItem.Header>
<StackPanel Orientation="Horizontal">
<Image Height="18" Source="pepperoni.jpg" />
<TextBlock Text="Pepperoni" Margin="2,0,0,0" VerticalAlignment="Center" />
</StackPanel>
</TabItem.Header>
</TabItem>
<TabItem>
<TabItem.Header>
<StackPanel Orientation="Horizontal">
<Image Height="18" Source="mushrooms.jpg" />
<TextBlock Text="Mushrooms" Margin="2,0,0,0" VerticalAlignment="Center" />
</StackPanel>
</TabItem.Header>
</TabItem>
</TabControl>
</Grid>
</Window>
And that makes something that looks like the image below.
With the techniques above, you should be able to do almost anything you
need with a tab control. What you can't do, however, is change how the
underlining tab control looks. Fortunately, WPF's style system makes
modifying how the tab control looks fairly easy. By default, the color
of the tabs themselves will follow the theme of the Windows machine
they're running on. Let's start off by modifying the color and shape of
the tabs.
The first thing we need to do is define a
style
for the TabItem control. Styles for WPF are similar to what CSS is for
web pages, except much more powerful.
<Window x:Class="TabControlTutorial.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="WPF Tabs" Height="281" Width="454">
<Window.Resources>
<Style TargetType="{x:Type TabItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Grid>
<Border
Name="Border"
Background="LightBlue"
BorderBrush="Black"
BorderThickness="1,1,1,1"
CornerRadius="6,6,0,0" >
<ContentPresenter x:Name="ContentSite"
VerticalAlignment="Center"
HorizontalAlignment="Center"
ContentSource="Header"
Margin="12,2,12,2"/>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>
<TabControl>
<TabItem Header="Cheese" />
<TabItem Header="Pepperoni" />
<TabItem Header="Mushrooms" />
</TabControl>
</Grid>
</Window>
Styles are defined up in the resources for your control - in this case
the Window that holds my tab control. There's a lot going on here, and
most of it I stole from this MSDNarticle. Let's
step through this tag-by-tag.
<Style TargetType="{x:Type TabItem}">
Here we are defining a style for a specific type of control - the
TabItem. Any TabItem that appears in this window will use this style.
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
This style is simply setting the Template property of the TabItem. The
template can hold most types of WPF controls, so you can make it look
pretty much like anything you want.
<Grid>
<Border
Name="Border"
Background="LightBlue"
BorderBrush="Black"
BorderThickness="1,1,1,1"
CornerRadius="6,6,0,0" >
<ContentPresenter x:Name="ContentSite"
VerticalAlignment="Center"
HorizontalAlignment="Center"
ContentSource="Header"
Margin="12,2,12,2"/>
</Border>
</Grid>
For this template, we simply put a grid and a border to give the tab a
background color and some rounded corners. The
ContentPresenter
is there to display the content of our TabItem - in this case whatever
you put in the Header. With this style applied to the Tab Control, our
application now looks like the following:
Not too bad, but you may have noticed that deselected tabs aren't
distinguished from selected tabs. This is because when you override the
style of a Tab Item, you're now responsible for everything. This is
easily implemented with
Triggers.
<Style TargetType="{x:Type TabItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Grid>
<Border
Name="Border"
Background="LightBlue"
BorderBrush="Black"
BorderThickness="1,1,1,1"
CornerRadius="6,6,0,0" >
<ContentPresenter x:Name="ContentSite"
VerticalAlignment="Center"
HorizontalAlignment="Center"
ContentSource="Header"
Margin="12,2,12,2"/>
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="Border" Property="Background" Value="LightBlue" />
</Trigger>
<Trigger Property="IsSelected" Value="False">
<Setter TargetName="Border" Property="Background" Value="LightGray" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
When a TabItem is clicked, its IsSelected property gets set to true. So
what we have to do is add triggers watching the IsSelected property.
When the property becomes true, the background color is set to light
blue. When it's false, the background color is changed to light gray.
Now we've got something that looks like this:
I think we've got pretty good control over the tabs. Now I want to
change how the background and borders look on the tab contents. The
style for the tab control is very similar to what we just did for the
tab items.
<Style TargetType="{x:Type TabControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabControl}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TabPanel
Grid.Row="0"
Panel.ZIndex="1"
Margin="0,0,4,-1"
IsItemsHost="True"
Background="Transparent" />
<Border
Grid.Row="1"
BorderBrush="Black"
BorderThickness="1"
CornerRadius="0, 12, 12, 12" >
<Border.Background>
<LinearGradientBrush>
<GradientStop Color="LightBlue" Offset="0" />
<GradientStop Color="White" Offset="1" />
</LinearGradientBrush>
</Border.Background>
<ContentPresenter ContentSource="SelectedContent" />
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
With that code we now have a tab control that looks like this:
I think that about does it for the WPF TabControl. In this tutorial
you've learned how to create and populate a basic tab control as well as
more advanced techniques for styling the tabs and tab contents. I think
the learning curve for WPF styles is a little steep, but once you
understand it, you can see how powerful it is. The best thing, however,
is that I didn't have to write any C# code to skin my tab control.
Comments
Post a Comment