Introduction
I saw a Google Chrome extension called Yoono. Basically, it has a list box containing
tweets or status updates. One thing I noticed is how the list box’s scrollbar
is styled.

Figure 1. Scrollbar Style in Yoono
Figure 1 shows cropped images of the list box taken at different times. When the
mouse is outside the bounds of the list box, the scrollbar is not shown. If the
user moves the mouse inside the list box, a small scrollbar will appear. When
the user moves the mouse over this scrollbar, the scrollbar will become larger.
I thought of applying this behavior to a WPF ScrollViewer.
Get the Default ScrollViewer Style
The first thing we usually do when restyling a control is to get the default style
of the control and modify it instead of starting from scratch. The default style
of the ScrollViewer is shown below.
<Style x:Key="{x:Type ScrollViewer}"
TargetType="{x:Type ScrollViewer}">
<Style.Triggers>
<Trigger Property="IsEnabled"
Value="false">
<Setter Property="Foreground"
Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
</Trigger>
</Style.Triggers>
</Style>
Listing 1. ScrollViewer Default Style
You might have thought that the ScrollViewer’s default template contains two ScrollBar
controls, vertical and horizontal. Actually, the ScrollBar controls are added
via code, in the ScrollViewer’s static constructor. If we translate the code
to XAML, the default template would look something like this.
<ControlTemplate TargetType="{x:Type ScrollViewer}">
<Grid Background="{TemplateBinding Background}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<ScrollBar
x:Name="PART_VerticalScrollBar"
Grid.Column="1"
Minimum="0.0"
Maximum="{TemplateBinding ScrollableHeight}"
ViewportSize="{TemplateBinding ViewportHeight}"
Value="{Binding RelativeSource={RelativeSource TemplatedParent},
Path=VerticalOffset, Mode=OneWay}"
Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}"
Cursor="Arrow"
AutomationProperties.AutomationId="VerticalScrollBar"/>
<ScrollBar
x:Name="PART_HorizontalScrollBar"
Orientation="Horizontal"
Grid.Row="1"
Minimum="0.0"
Maximum="{TemplateBinding ScrollableWidth}"
ViewportSize="{TemplateBinding ViewportWidth}"
Value="{Binding RelativeSource={RelativeSource TemplatedParent},
Path=HorizontalOffset, Mode=OneWay}"
Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}"
Cursor="Arrow"
AutomationProperties.AutomationId="HorizontalScrollBar"/>
<ScrollContentPresenter
x:Name="PART_ScrollContentPresenter"
Margin="{TemplateBinding Padding}"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
CanContentScroll="{TemplateBinding CanContentScroll}"/>
<Rectangle
x:Name="Corner"
Grid.Column="1"
Grid.Row="1"
Fill="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
</Grid>
</ControlTemplate>
Listing 2. Default ScrollViewer Template in XAML
Other controls, like the DataGrid, override the default template of the ScrollViewer.
It means that in case we want to modify the ScrollViewer in the DataGrid, we
have to change the DataGrid style also. Modifying the default template of the
ScrollViewer does not mean that it will get applied to ScrollViewers used by
other controls. For this article, we will just delve on modifying the default
template.
Hide and Show ScrollBars
For demonstration purposes, I created a WPF application with a ScrollViewer containing
an Image.

Figure 2. Demo WPF Application
In the default ScrollViewer template, the Grid has four cells for the following:
ScrollViewer content, vertical scrollbar, horizontal scrollbar, and a rectangle.
Since we want the ScrollBars to be semi-transparent over the ScrollViewer content,
we can put the ScrollBars on a separate Grid that will overlap with the other
Grid. The Rectangle in the default template can also be removed. The Rectangle
just fills the lower-right corner with gray color. The following listing shows
the modified ScrollViewer style.
<Style x:Key="{x:Type ScrollViewer}"
TargetType="{x:Type ScrollViewer}">
<Setter Property="HorizontalScrollBarVisibility" Value="Hidden"/>
<Setter Property="VerticalScrollBarVisibility" Value="Hidden"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ScrollViewer}">
<Grid>
<Grid Background="{TemplateBinding Background}">
<ScrollContentPresenter
x:Name="PART_ScrollContentPresenter"
Margin="{TemplateBinding Padding}"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
CanContentScroll="{TemplateBinding CanContentScroll}"/>
</Grid>
<Grid Background="Transparent">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<ScrollBar
x:Name="PART_VerticalScrollBar"
Grid.Column="1"
Minimum="0.0"
Maximum="{TemplateBinding ScrollableHeight}"
ViewportSize="{TemplateBinding ViewportHeight}"
Value="{Binding RelativeSource={RelativeSource TemplatedParent},
Path=VerticalOffset, Mode=OneWay}"
Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}"
Cursor="Arrow"
AutomationProperties.AutomationId="VerticalScrollBar"/>
<ScrollBar
x:Name="PART_HorizontalScrollBar"
Orientation="Horizontal"
Grid.Row="1"
Minimum="0.0"
Maximum="{TemplateBinding ScrollableWidth}"
ViewportSize="{TemplateBinding ViewportWidth}"
Value="{Binding RelativeSource={RelativeSource TemplatedParent},
Path=HorizontalOffset, Mode=OneWay}"
Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}"
Cursor="Arrow"
AutomationProperties.AutomationId="HorizontalScrollBar"/>
</Grid>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsEnabled"
Value="false">
<Setter Property="Foreground"
Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
</Trigger>
<Trigger Property="IsMouseOver"
Value="true">
<Setter Property="HorizontalScrollBarVisibility"
Value="Visible"/>
<Setter Property="VerticalScrollBarVisibility"
Value="Visible"/>
</Trigger>
</Style.Triggers>
</Style>
Listing 3. Modified ScrollViewer Style
In the modified style, the HorizontalScrollBarVisibility and VerticalScrollBarVisibility
properties are set to Hidden. A trigger is used so that when the IsMouseOver
property is set to True, the ScrollBars will be visible. The Background of the
upper-layer Grid is set to Transparent so that the ScrollViewer content is not
blocked from view.

Figure 3. Showing ScrollBars When Mouse is Over the ScrollViewer
The first window in Figure 3 has no ScrollBars since the mouse is outside the window.
In the second window, the ScrollBars are visible because the mouse is inside
the ScrollViewer. The ScrollBars still look the same as we still have not changed
the ScrollBar template yet. Let’s try making the small version of the ScrollBar.
Small ScrollBars
Same thing with the ScrollViewer, we can get the default style of the ScrollBar control
and modify the template to make the ScrollBar look smaller. I would like to show
the default style here to show the differences with the modified style but it
is quite long. If you like to see the default ScrollBar style, you can use a
tool to get it or download the WPF Themes on this site: http://code.msdn.microsoft.com/wpfsamples#.
The following listing shows a modified vertical ScrollBar template. The horizontal
ScrollBar template is very similar so there is no need to show it here.
<ControlTemplate TargetType="{x:Type ScrollBar}">
<Border
x:Name="Bg"
CornerRadius="2"
Margin="2"
Opacity="0.75"
Background="{TemplateBinding Background}"
VerticalAlignment="Bottom">
<Grid
SnapsToDevicePixels="true">
<Grid.RowDefinitions>
<RowDefinition MaxHeight="{DynamicResource {x:Static SystemParameters.VerticalScrollBarButtonHeightKey}}"/>
<RowDefinition MaxHeight="{DynamicResource {x:Static SystemParameters.VerticalScrollBarButtonHeightKey}}"/>
</Grid.RowDefinitions>
<RepeatButton
Style="{StaticResource ScrollBarButton}"
Background="#FFCBCBCB"
IsEnabled="{TemplateBinding IsMouseOver}"
Command="{x:Static ScrollBar.LineUpCommand}"
theme:ScrollChrome.ScrollGlyph="UpArrow"
Margin="0,4"/>
<RepeatButton
Style="{StaticResource ScrollBarButton}"
Background="#FFCBCBCB"
Grid.Row="1"
IsEnabled="{TemplateBinding IsMouseOver}"
Command="{x:Static ScrollBar.LineDownCommand}"
theme:ScrollChrome.ScrollGlyph="DownArrow"
Margin="0,4">
</RepeatButton>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled"
Value="false">
<Setter TargetName="Bg"
Property="Visibility"
Value="Hidden"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
Listing 4. Modified ScrollBar Style
In the default template, the Track which contains the ScrollBar Thumb control is
sandwiched between two RepeatButtons. In the modified template, the Track is
removed and now only contains the two RepeatButtons. The Track will be shown
when the mouse is over the ScrollBar. On the other hand, we still haven’t changed
the template of the RepeatButtons. The default RepeatButton template is shown
below.
<ControlTemplate TargetType="{x:Type RepeatButton}">
<theme:ScrollChrome Name="Chrome"
ScrollGlyph="{TemplateBinding theme:ScrollChrome.ScrollGlyph}"
RenderMouseOver="{TemplateBinding IsMouseOver}"
RenderPressed="{TemplateBinding IsPressed}"
SnapsToDevicePixels="true"/>
</ControlTemplate>
Listing 5. ScrollBarButton Style
Since a ScrollChrome is used as the template, nothing much could be done but to remove
it and supply a different template. We only need to specify an arrow shape in
the template.
<ControlTemplate TargetType="{x:Type RepeatButton}">
<Path x:Name="Arrow" HorizontalAlignment="Center" VerticalAlignment="Center" Fill="{TemplateBinding Background}"/>
<ControlTemplate.Triggers>
<Trigger Property="theme:ScrollChrome.ScrollGlyph" Value="UpArrow">
<Setter TargetName="Arrow" Property="Data" Value="M 3,0 l 3,8 l -6,0 Z"/>
</Trigger>
<Trigger Property="theme:ScrollChrome.ScrollGlyph" Value="DownArrow">
<Setter TargetName="Arrow" Property="Data" Value="M 0,0 l 6,0 l -3,8 Z"/>
</Trigger>
<Trigger Property="theme:ScrollChrome.ScrollGlyph" Value="LeftArrow">
<Setter TargetName="Arrow" Property="Data" Value="M 0,3 l 8,-3 l 0,6 Z"/>
</Trigger>
<Trigger Property="theme:ScrollChrome.ScrollGlyph" Value="RightArrow">
<Setter TargetName="Arrow" Property="Data" Value="M 0,0 l 8,3 l -8,3 Z"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
Listing 6. Arrow Template
In here, the Path shape is used to create the arrows. Triggers determine the direction
of the arrow and set the Path data accordingly. The ScrollGlyph property is reused
so that we don’t have to define our own enumeration for the arrow directions.
It also means that we don’t have to modify the RepeatButtons that use the ScrollGlyph
property. Meanwhile, in the ScrollBar template, a Border is added to serve as
the background for the arrows. Some margins were also added.

Figure 4. Small ScrollBar
Lastly, we need to show the larger version of the ScrollBar when the mouse is over
it.
Large ScrollBars
Remember in Listing 4 that we specified a small ScrollBar as the template. When the
IsMouseOver property of the ScrollBar is set to true, we can set the template
to the large version of the ScrollBar. The following code listing shows the trigger
that accomplishes this for the vertical ScrollBar.
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsMouseOver" Value="True"/>
<Condition Property="Orientation" Value="Vertical"/>
</MultiTrigger.Conditions>
<MultiTrigger.Setters>
<Setter Property="Width"
Value="30"/>
<Setter
Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ScrollBar}">
<Border
CornerRadius="4"
Margin="2"
Opacity="0.75"
Background="{TemplateBinding Background}">
<Grid
SnapsToDevicePixels="true">
<Grid.RowDefinitions>
<RowDefinition Height="0.00001*"/>
<RowDefinition MaxHeight="{DynamicResource {x:Static SystemParameters.VerticalScrollBarButtonHeightKey}}"/>
<RowDefinition MaxHeight="{DynamicResource {x:Static SystemParameters.VerticalScrollBarButtonHeightKey}}"/>
</Grid.RowDefinitions>
<Track
Name="PART_Track"
IsEnabled="{TemplateBinding IsMouseOver}"
IsDirectionReversed="true">
<Track.DecreaseRepeatButton>
<RepeatButton Style="{StaticResource VerticalScrollBarPageButton}"
Command="{x:Static ScrollBar.PageUpCommand}"/>
</Track.DecreaseRepeatButton>
<Track.IncreaseRepeatButton>
<RepeatButton Style="{StaticResource VerticalScrollBarPageButton}"
Command="{x:Static ScrollBar.PageDownCommand}"/>
</Track.IncreaseRepeatButton>
<Track.Thumb>
<Thumb Style="{StaticResource ScrollBarThumb}"
theme:ScrollChrome.ScrollGlyph="VerticalGripper"
Margin="2"/>
</Track.Thumb>
</Track>
<RepeatButton
Style="{StaticResource ScrollBarButton}"
Background="#FFFFFFFF"
Grid.Row="1"
IsEnabled="{TemplateBinding IsMouseOver}"
Command="{x:Static ScrollBar.LineUpCommand}"
theme:ScrollChrome.ScrollGlyph="UpArrow"
RenderTransformOrigin="0.5, 0.5">
<RepeatButton.RenderTransform>
<ScaleTransform ScaleX="1.5" ScaleY="1.5"/>
</RepeatButton.RenderTransform>
</RepeatButton>
<RepeatButton
Style="{StaticResource ScrollBarButton}"
Background="#FFFFFFFF"
Grid.Row="2"
IsEnabled="{TemplateBinding IsMouseOver}"
Command="{x:Static ScrollBar.LineDownCommand}"
theme:ScrollChrome.ScrollGlyph="DownArrow"
RenderTransformOrigin="0.5, 0.5">
<RepeatButton.RenderTransform>
<ScaleTransform ScaleX="1.5" ScaleY="1.5"/>
</RepeatButton.RenderTransform>
</RepeatButton>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</MultiTrigger.Setters>
</MultiTrigger>
Listing 7. Large ScrollBar Template
A MultiTrigger is used because we have to take into consideration the IsMouseOver
and Orientation properties. The most noticeable difference of this template compared
to that in Listing 4 is the addition of the Track. A ScaleTransform is also applied
to both RepeatButtons so that the arrows look larger. The ScrollBar Thumb control
default template uses a ScrollChrome also. I changed this to a Border and just
set the appropriate Background and CornerRadius values to make the ScrollBar
look similar to that in Figure 1.

Figure 5. Large ScrollBar
That’s it. We now have a different-styled ScrollViewer. Using WPF, we easily copied
the style that we want and do it using only XAML. You can download the Visual
Studio 2010 solution here.