Click here to Skip to main content
15,868,016 members
Articles / Desktop Programming / WPF

Creating a Blend like Scrollbar

Rate me:
Please Sign up or sign in to vote.
4.88/5 (18 votes)
26 Aug 2009CPOL5 min read 65.3K   3.5K   41   10
This article shows how to style a scrollbar to look like the scrollbars in expression blend

Introduction

I'm building a messaging application. This application is a SOA desktop application written in C# that uses WPF. At some point in time, I thought that it would be nice if my application had a black based theme like the one expression blend uses. I started with the scrollbar and this is what I'm going to talk about in this article: how to style a scrollbar so that it looks like the scrollbars in expression blend. I styled both the horizontal and vertical scrollbars. The downloadable code also includes styles for a listbox that uses both the scrollbars (so that the scrollbar would look better:)).

Background

I guess the reader should have a basic knowledge of styles and templates. If the reader is also going to read the styles for the list box, he/she should also know some basics about animations.

Brushes

The sample uses the following brushes:  

XML
<SolidColorBrush x:Key="StandardBorderBrush" Color="DarkGray"></SolidColorBrush>
<SolidColorBrush x:Key="StandardBrush" Color="LightGray"></SolidColorBrush>
<SolidColorBrush x:Key="PressedBrush" Color="Gray"></SolidColorBrush>
<SolidColorBrush x:Key="HoverBrush" Color="#fefefe"></SolidColorBrush>
<SolidColorBrush x:Key="GlyphBrush" Color="333333"></SolidColorBrush>

The Scroll Bar Structure 

As most of us already know, a scrollbar is not as easy to style as a button for example. This is because the scrollbar has about 6 components that need to be addressed. You can see them in the picture below:

To properly style the scrollbar, I used styles for: the repeat buttons that move the data one line at a time (one style for each), a style for the thumb and a style for the transparent repeat buttons (one for both).  

At the end, the scrollbars will look like the images below. On the left, you can see the entire window and on the right, you can see the 3 states of the scrollbar: normal, hover and pressed. 

The Vertical Scroll Bar

This scrollbar is defined using a 3 row grid. The up button is on the first row, the track is on the second row and the down button is on the third row. The style for the up button can be seen in the following markup: 

XML
<Style x:Key="LineButtonUpStyle" TargetType="{x:Type RepeatButton}">
<Setter Property="Focusable" Value="False"/>
<Setter Property="Template">
      <Setter.Value>
        <ControlTemplate TargetType="{x:Type RepeatButton}">
           <Grid Margin="1" Height="18" >
        <Path Stretch="None"
HorizontalAlignment="Center"
VerticalAlignment="Center" Name="Path"  
Fill="{StaticResource
StandardBrush}"
  Data="M0 0L 8 8 L 4 0 Z"></Path>
         </Grid>
          <ControlTemplate.Triggers>                       
          <Trigger Property="IsMouseOver" Value="true">
  <Setter TargetName="Path" Property="Fill"
Value="{StaticResource HoverBrush}" />
         </Trigger>
     <Trigger Property="IsPressed" Value="true">
     <Setter TargetName="Path" Property="Fill"
Value="{StaticResource PressedBrush}" />
      </Trigger>
       </ControlTemplate.Triggers>
     </ControlTemplate>
     </Setter.Value>
        </Setter>
    </Style> 

As you can see, this button shows a path element that represents a triangle. This triangle is placed in the center of the button using the alignment properties. Also this button has 2 triggers. When the mouse hovers over the button, the triangle gets a lighter brush (HoverBrush) and when the button is pressed, the triangle is given a darker brush (PressedBrush).

The style for the down buton is very similar. The only difference is the orientation of the triangle. This one points down. The style can be seen below. The differences are in bold.

XML
<Style x:Key="LineButtonDownStyle"
TargetType="{x:Type RepeatButton}">
         <Setter Property="Focusable"
Value="False"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type
RepeatButton}">  
<Grid Margin="1"
Height="18" >
      <Path Stretch="None" HorizontalAlignment="Center"

    VerticalAlignment="Center" Name="Path"  Fill="{StaticResource
StandardBrush}"

   Data="M 0 0 L 4 8 L 8 0 Z"></Path></Grid>
             <ControlTemplate.Triggers>
                   <Trigger Property="IsMouseOver" Value="true">
                            <Setter TargetName="Path" Property="Fill"
                                    Value="{StaticResource HoverBrush}" />
                        </Trigger>
                        <Trigger Property="IsPressed" Value="true">
                            <Setter TargetName="Path" Property="Fill"
                                    Value="{StaticResource PressedBrush}" />
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

The style for the other 2 repeat buttons (the transparent ones) is very simple. It sets the template of the button to a transparent border. You can see this style below:

XML
<Style x:Key="ScrollBarPageButtonStyle"
TargetType="{x:Type RepeatButton}">
        <Setter Property="IsTabStop" Value="False"/>
        <Setter Property="Focusable" Value="False"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type RepeatButton}">
                    <Border Background="Transparent"/>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

The style for the thumb can be seen below:

XML
<Style x:Key="VerticalScrollBarThumbStyle"
TargetType="{x:Type Thumb}">

        <Setter Property="IsTabStop"
Value="False"/>
        <Setter Property="Focusable"
Value="False"/>
     <Setter Property="Margin"
Value="1,0,1,0" />
        <Setter Property="BorderBrush" Value="{StaticResource StandardBorderBrush}" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Thumb}">
             <Rectangle Width="8" Name="ellipse"  Stroke="{StaticResource
StandardBorderBrush}"
Fill="{StaticResource StandardBrush}"
           RadiusX="5" RadiusY="5"></Rectangle>
            <ControlTemplate.Triggers>
                <Trigger Property="IsMouseOver" Value="true">
<Setter TargetName="ellipse"
Property="Fill" Value="{StaticResource HoverBrush}"></Setter>
                        </Trigger>
                <Trigger Property="IsDragging" Value="True">
           <Setter TargetName="ellipse"
Property="Fill" Value="{StaticResource PressedBrush}"></Setter>
                        </Trigger>                       
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

As you can see from the style above, the thumb is an 8 pixel wide rectangle named ellipse(because I originally wanted to use an ellipse and I didn’t change it). The thumb also has 2 triggers. When the mouse hovers over the thumb, the thumb gets a lighter brush (HoverBrush). When the user drags the thumb, it gets a darker brush (PressedBrush).

In order to build the scrollbar, all the above styles need to be used. Like I said before, the scrollbar is a three row grid that has a very subtle linear gradient background.

XML
<ControlTemplate x:Key="VerticalScrollBar" TargetType="{x:Type ScrollBar}">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition MaxHeight="18"/>
                <RowDefinition Height="*"/>
                <RowDefinition MaxHeight="18"/>
            </Grid.RowDefinitions>
            <Grid.Background>
                <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
              <GradientStop Offset="0" Color="#4c4c4c"></GradientStop>
              <GradientStop Offset="1" Color="#434343"></GradientStop>
                </LinearGradientBrush>
            </Grid.Background>

On the first row, we have the up button.

XML
<RepeatButton Grid.Row="0" Height="18"
      Style="{StaticResource LineButtonUpStyle}"

Command="ScrollBar.LineUpCommand">  
</RepeatButton>

As you can see, this is a repeat button that uses the LineButtonUpStyle style discussed before (the one with the triangle pointing up).

On the second row, we have the track of the scrollbar. This track has to have a special name (PART_Track).

XML
<Track Name="PART_Track" Grid.Row="1" IsDirectionReversed="True">
      <Track.DecreaseRepeatButton>
             <RepeatButton Command="ScrollBar.PageUpCommand"
              Style="{StaticResource ScrollBarPageButtonStyle}">
</RepeatButton>
      </Track.DecreaseRepeatButton>
      <Track.Thumb>
            <Thumb Style="{StaticResource VerticalScrollBarThumbStyle}">
            </Thumb>
      </Track.Thumb>
      <Track.IncreaseRepeatButton>
             <RepeatButton Command="ScrollBar.PageDownCommand"
                   Style="{StaticResource ScrollBarPageButtonStyle}">
             </RepeatButton>
       </Track.IncreaseRepeatButton>
</Track>

As you can see from the XAML above, the track has 3 parts. The decrease value part at the top, the thumb in the middle and the increase value part at the bottom. The increase and decrease parts use a repeat button that uses the transparent style. The thumb uses its own style described previously.

Here I need to mention something else: the IsDirectionReversed property. It looks like if I don’t set this to true, the thumb starts at the bottom of the scrollbar.

Finally, on the last row, we have another repeat button (the one with the triangle pointing down).

XML
<RepeatButton Grid.Row="2" Height="18" Style="{StaticResource LineButtonDownStyle}"
        Command="ScrollBar.LineDownCommand">
</RepeatButton>  

The Horizontal Scroll Bar

The horizontal scrollbar has a similar structure. The XAML below shows you the markup for the template.

XML
<ControlTemplate x:Key="HorizontalScrollBar"
TargetType="{x:Type ScrollBar}">
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition MaxWidth="18"></ColumnDefinition>
                <ColumnDefinition Width="*"></ColumnDefinition>
                <ColumnDefinition MaxWidth="18"></ColumnDefinition>
            </Grid.ColumnDefinitions>
            <Grid.Background>
                <LinearGradientBrush StartPoint="0,0" EndPoint="1,0">
                <GradientStop Offset="0" Color="#4c4c4c"></GradientStop>
                    <GradientStop Offset="1" Color="#434343"></GradientStop>
            </LinearGradientBrush>
            </Grid.Background>
            <RepeatButton Grid.Column="0" Width="18"
     Style="{StaticResource LineButtonLeftStyle}"
 Command="ScrollBar.LineLeftCommand">
         </RepeatButton>
            <Track Name="PART_Track"
Grid.Column="1" IsDirectionReversed="False" >
       <Track.DecreaseRepeatButton>
                    <RepeatButton Command="ScrollBar.PageLeftCommand"
                        Style="{StaticResource
ScrollBarPageButtonStyle}">
                    </RepeatButton>
                </Track.DecreaseRepeatButton>
                <Track.Thumb>
                    <Thumb Style="{StaticResource HorizontalScrollBarThumbStyle}">
                    </Thumb>
                </Track.Thumb>
                <Track.IncreaseRepeatButton>
                    <RepeatButton Command="ScrollBar.PageRightCommand"
                        Style="{StaticResource ScrollBarPageButtonStyle}">
                    </RepeatButton>
                </Track.IncreaseRepeatButton>
            </Track>
            <RepeatButton Grid.Column="2" Width="18"
 Style="{StaticResource
LineButtonRightStyle}"
                Command="ScrollBar.LineRightCommand">
            </RepeatButton>
        </Grid>
    </ControlTemplate>

As you can see, this time we have a 3 column grid. The first column holds the scroll left repeat button, the second column contains the track and the last column contains the scroll right repeat button. The styles used here are almost the same with the ones used for the vertical scrollbar. The triggers are exactly the same. The only differences are the orientation of the triangles (they point left and right), and the dimensions of the thumb rectangle. One last thing to notice here is that the IsDirectionReversed property is left to false

The Scroll Bar Style 

These 2 templates will be used to set the template for the scrollbar. This is applied using a style. You can see this below:

XML
<Style TargetType="{x:Type ScrollBar}">
        <Setter Property="SnapsToDevicePixels" Value="True"/>
        <Setter Property="OverridesDefaultStyle" Value="true"/>       
<Style.Triggers>
           <Trigger Property="Orientation" Value="Vertical">
               <Setter Property="Width" Value="18"/>
            <Setter Property="Height" Value="Auto" />
           <Setter Property="Template" Value="{StaticResource VerticalScrollBar}" />
            </Trigger>
            <Trigger Property="Orientation" Value="Horizontal">
                <Setter Property="Width" Value="Auto"/>
       <Setter Property="Height" Value="18" />
               <Setter Property="Template" Value="{StaticResource HorizontalScrollBar}" />
           </Trigger>
        </Style.Triggers></Style>

As you can see from the above XAML, if the orientation is vertical the style for the vertical scrollbar will use the VerticalScrollBar template and if the orientation is horizontal the HorizontalScrollBar template will be used. One last thing to mention is that I chose to use separate templates for the 4 scroll buttons (left, right, up and down) because the brush for the triangles needs to change. If, on the other hand,the background of the buttons had to change this could have been done with a single template like the transparent buttons.

Something About the List Box Style 

Also please check out the styles for the list box because they contain something very cool. A way to style the rectangle in the bottom right corner of the listbox (the one at the intersection of the 2 scrollbars).

If you look at a default template of a scroll viewer, you will notice that this rectangle is named ‘corner’ and uses a brush with the following key:

XML
x:Key="{x:Static SystemColors.ControlBrushKey}"

The template adds a resource with the same name in order to override the default color. This takes advantage of the way WPF searches for resources: from the element outward. This is it. Hope you like the article.

History

  • Added on Wednesday, 26 August, 2009 

License

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


Written By
Software Developer
Romania Romania
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionThanks! Pin
DarknessMA15-Jan-19 4:36
DarknessMA15-Jan-19 4:36 
PraiseThanks Pin
Member 1320897118-May-17 6:10
Member 1320897118-May-17 6:10 
QuestionThanks... Pin
1.21 Gigawatts22-Aug-14 4:21
1.21 Gigawatts22-Aug-14 4:21 
QuestionCan you provide this scroll bar theme for silverlight Pin
thanki.kaushik3-Apr-14 6:41
thanki.kaushik3-Apr-14 6:41 
GeneralMy vote of 5 Pin
Joezer BH23-May-13 2:21
professionalJoezer BH23-May-13 2:21 
GeneralMy vote of 5 Pin
zygadlo20-Sep-12 3:01
zygadlo20-Sep-12 3:01 
Questionthanks Pin
lio1019-Mar-12 11:08
lio1019-Mar-12 11:08 
GeneralNice one Pin
lstevensuk24-Nov-09 10:59
lstevensuk24-Nov-09 10:59 
GeneralExcelent! Pin
Andrei Ion Rînea31-Aug-09 22:07
Andrei Ion Rînea31-Aug-09 22:07 
GeneralWow I like this Pin
Anthony Daly26-Aug-09 23:25
Anthony Daly26-Aug-09 23:25 

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.