Click here to Skip to main content
15,886,258 members
Articles / Desktop Programming / WPF

Styling a ScrollViewer/Scrollbar In WPF

Rate me:
Please Sign up or sign in to vote.
4.94/5 (32 votes)
17 Jun 2009CPOL2 min read 360.4K   3.5K   57   33
Styling a ScrollViewer/Scrollbar In WPF

A while ago, I was looking at the Infragistics WPF showcase, Tangerine and I was quite jealous about the scrollbars that they managed to use. I mean styling a Button is one thing, but the ScrollBar is made of lots of nasty different control parts, (Part_XXX elements). Incidentally, I wrote an article about Part_XXX elements in a WPF article over at CodeProject right here if you are interested.

Anyways, to cut a long story short, I decided to try and have a go at Styling a bigger control such as ScrollViewer. And guess what I managed to do it. Hooray!

This is what it looks like:

37366/newstyle.png37366/origstyle.png
My Styled ScrollViewer
Original ScrollViewer

This blog entry outlines the steps I went through.

Step 1

Look up and copy the original ScrollViewer and ScrollBar Templates from MSDN, for example:

Then I pasted that code from MSDN into a Resources file in a WPF window.

Step 2

I examined the control parts required for the full ScrollViewer/Scrollbar controls. This was fairly ok actually as the MSDN default Styles and pretty easy to follow.

From looking at the default styles, it became clear that I needed to look at the following Style/Templates if I wished to re-style a ScrollViewer, as all of these were used in the default Style for the ScrollViewer somewhere.

Step 3

I then decided which parts I want to swap out. I chose to swap out and proceeded to hack the default Style/Templates to achieve the look I was after.

Anyway, the results ScrollViewer looks like the following image:

  • RepeatButton
  • Thumb
  • ScrollBar
  • ScrollViewer

     

When you consider the following image, you can see why these are the Style/Templates that need to be altered.

37366/scroll.png

So basically after that, it's just a question of cutting code. So without further ado, here is the code:

XML
<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006″
    x:Class="ScrollViewerTemplate.Window1″
    x:Name="Window"
    Title="Window1″
    Width="200″ Height="200″>

  <Window.Resources>

        <!– All the following is required to Re-Style the ScrollViewer, see 
             http://msdn2.microsoft.com/en-us/library/aa970847(VS.85).aspx
             http://msdn2.microsoft.com/en-us/library/ms742173(VS.85).aspx
             for the default Styles that the ScrollViewer has out of the box
         –>

        <!– Brushes used in Styling of ScrollViewer –>
        <SolidColorBrush x:Key="StandardBorderBrush" Color="#888″ />
        <SolidColorBrush x:Key="StandardBackgroundBrush" Color="#FFF" />
        <SolidColorBrush x:Key="HoverBorderBrush" Color="#DDD" />
        <SolidColorBrush x:Key="SelectedBackgroundBrush" Color="Gray" />
        <SolidColorBrush x:Key="SelectedForegroundBrush" Color="White" />
        <SolidColorBrush x:Key="DisabledForegroundBrush" Color="#888″ />
        <SolidColorBrush x:Key="NormalBrush" Color="#888″ />
        <SolidColorBrush x:Key="NormalBorderBrush" Color="#888″ />
        <SolidColorBrush x:Key="HorizontalNormalBrush" Color="#888″ />
        <SolidColorBrush x:Key="HorizontalNormalBorderBrush" Color="#888″ />
        <LinearGradientBrush x:Key="ListBoxBackgroundBrush"
            StartPoint="0,0″ EndPoint="1,0.001″>
            <GradientBrush.GradientStops>
                <GradientStopCollection>
                    <GradientStop Color="White" Offset="0.0″ />
                    <GradientStop Color="White" Offset="0.6″ />
                    <GradientStop Color="#DDDDDD" Offset="1.2″/>
                </GradientStopCollection>
            </GradientBrush.GradientStops>
        </LinearGradientBrush>
        <LinearGradientBrush x:Key="StandardBrush"
            StartPoint="0,0″ EndPoint="0,1″>
            <GradientBrush.GradientStops>
                <GradientStopCollection>
                    <GradientStop Color="#FFF" Offset="0.0″/>
                    <GradientStop Color="#CCC" Offset="1.0″/>
                </GradientStopCollection>
            </GradientBrush.GradientStops>
        </LinearGradientBrush>
        <SolidColorBrush x:Key="GlyphBrush" Color="#444″ />
        <LinearGradientBrush x:Key="PressedBrush"
            StartPoint="0,0″ EndPoint="0,1″>
            <GradientBrush.GradientStops>
                <GradientStopCollection>
                    <GradientStop Color="#BBB" Offset="0.0″/>
                    <GradientStop Color="#EEE" Offset="0.1″/>
                    <GradientStop Color="#EEE" Offset="0.9″/>
                    <GradientStop Color="#FFF" Offset="1.0″/>
                </GradientStopCollection>
            </GradientBrush.GradientStops>
        </LinearGradientBrush>

        <!– SrollViewer ScrollBar Repeat Buttons (at each end) –>
        <Style x:Key="ScrollBarLineButton" TargetType="{x:Type RepeatButton}">
            <Setter Property="SnapsToDevicePixels" Value="True"/>
            <Setter Property="OverridesDefaultStyle" Value="true"/>
            <Setter Property="Focusable" Value="false"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type RepeatButton}">
                        <Border
          Name="Border"
          Margin="1″
          CornerRadius="2″
          Background="{StaticResource NormalBrush}"
          BorderBrush="{StaticResource NormalBorderBrush}"
          BorderThickness="1″>
                            <Path
            HorizontalAlignment="Center"
            VerticalAlignment="Center"
            Fill="{StaticResource GlyphBrush}"
            Data="{Binding Path=Content,
                RelativeSource={RelativeSource TemplatedParent}}" />
                        </Border>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsPressed" Value="true">
                                <Setter TargetName="Border" Property="Background"
                                Value="{StaticResource PressedBrush}" />
                            </Trigger>
                            <Trigger Property="IsEnabled" Value="false">
                                <Setter Property="Foreground"
                                Value="{StaticResource DisabledForegroundBrush}"/>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
        <!– SrollViewer ScrollBar Repeat Buttons (The part in the middle, 
             not the thumb the long area between the buttons ) >
        <Style x:Key="ScrollBarPageButton" TargetType="{x:Type RepeatButton}">
            <Setter Property="SnapsToDevicePixels" Value="True"/>
            <Setter Property="OverridesDefaultStyle" Value="true"/>
            <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>
        <!– ScrollViewer ScrollBar Thumb, that part that can be dragged
            up/down or left/right Buttons >
        <Style x:Key="ScrollBarThumb" TargetType="{x:Type Thumb}">
            <Setter Property="SnapsToDevicePixels" Value="True"/>
            <Setter Property="OverridesDefaultStyle" Value="true"/>
            <Setter Property="IsTabStop" Value="false"/>
            <Setter Property="Focusable" Value="false"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type Thumb}">
                        <Border
          CornerRadius="2″
          Background="{TemplateBinding Background}"
          BorderBrush="{TemplateBinding BorderBrush}"
          BorderThickness="1″ />
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

        <ControlTemplate x:Key="VerticalScrollBar"
            TargetType="{x:Type ScrollBar}">
            <Grid >
                <Grid.RowDefinitions>
                    <RowDefinition MaxHeight="18″/>
                    <RowDefinition Height="0.00001*"/>
                    <RowDefinition MaxHeight="18″/>
                </Grid.RowDefinitions>
                <Border
      Grid.RowSpan="3″
      CornerRadius="2″
      Background="#F0F0F0″ />
                <RepeatButton
      Grid.Row="0″
      Style="{StaticResource ScrollBarLineButton}"
      Height="18″
      Command="ScrollBar.LineUpCommand"
      Content="M 0 4 L 8 4 L 4 0 Z" />
                <Track
      Name="PART_Track"
      Grid.Row="1″
      IsDirectionReversed="true">
                    <Track.DecreaseRepeatButton>
                        <RepeatButton
          Style="{StaticResource ScrollBarPageButton}"
          Command="ScrollBar.PageUpCommand" />
                    </Track.DecreaseRepeatButton>
                    <Track.Thumb>
                        <Thumb
          Style="{StaticResource ScrollBarThumb}"
          Margin="1,0,1,0″
          Background="{StaticResource HorizontalNormalBrush}"
          BorderBrush="{StaticResource HorizontalNormalBorderBrush}" />
                    </Track.Thumb>
                    <Track.IncreaseRepeatButton>
                        <RepeatButton
          Style="{StaticResource ScrollBarPageButton}"
          Command="ScrollBar.PageDownCommand" />
                    </Track.IncreaseRepeatButton>
                </Track>
                <RepeatButton
      Grid.Row="3″
      Style="{StaticResource ScrollBarLineButton}"
      Height="18″
      Command="ScrollBar.LineDownCommand"
      Content="M 0 0 L 4 4 L 8 0 Z"/>
            </Grid>
        </ControlTemplate>
        <!– HorizontalScrollBar Template using the previously created Templates >
        <ControlTemplate x:Key="HorizontalScrollBar"
            TargetType="{x:Type ScrollBar}">
            <Grid >
                <Grid.ColumnDefinitions>
                    <ColumnDefinition MaxWidth="18″/>
                    <ColumnDefinition Width="0.00001*"/>
                    <ColumnDefinition MaxWidth="18″/>
                </Grid.ColumnDefinitions>
                <Border
      Grid.ColumnSpan="3″
      CornerRadius="2″
      Background="#F0F0F0″ />
                <RepeatButton
      Grid.Column="0″
      Style="{StaticResource ScrollBarLineButton}"
      Width="18″
      Command="ScrollBar.LineLeftCommand"
      Content="M 4 0 L 4 8 L 0 4 Z" />
                <Track
      Name="PART_Track"
      Grid.Column="1″
      IsDirectionReversed="False">
                    <Track.DecreaseRepeatButton>
                        <RepeatButton
          Style="{StaticResource ScrollBarPageButton}"
          Command="ScrollBar.PageLeftCommand" />
                    </Track.DecreaseRepeatButton>
                    <Track.Thumb>
                        <Thumb
          Style="{StaticResource ScrollBarThumb}"
          Margin="0,1,0,1″
          Background="{StaticResource NormalBrush}"
          BorderBrush="{StaticResource NormalBorderBrush}" />
                    </Track.Thumb>
                    <Track.IncreaseRepeatButton>
                        <RepeatButton
          Style="{StaticResource ScrollBarPageButton}"
          Command="ScrollBar.PageRightCommand" />
                    </Track.IncreaseRepeatButton>
                </Track>
                <RepeatButton
      Grid.Column="3″
      Style="{StaticResource ScrollBarLineButton}"
      Width="18″
      Command="ScrollBar.LineRightCommand"
      Content="M 0 0 L 4 4 L 0 8 Z"/>
            </Grid>
        </ControlTemplate>
        <!– Style for overall  ScrollBar >
        <Style x:Key="{x:Type ScrollBar}" TargetType="{x:Type ScrollBar}">
            <Setter Property="SnapsToDevicePixels" Value="True"/>
            <Setter Property="OverridesDefaultStyle" Value="true"/>
            <Style.Triggers>
                <Trigger Property="Orientation" Value="Horizontal">
                    <Setter Property="Width" Value="Auto"/>
                    <Setter Property="Height" Value="18″ />
                    <Setter Property="Template"
                        Value="{StaticResource HorizontalScrollBar}" />
                </Trigger>
                <Trigger Property="Orientation" Value="Vertical">
                    <Setter Property="Width" Value="18″/>
                    <Setter Property="Height" Value="Auto" />
                    <Setter Property="Template"
                        Value="{StaticResource VerticalScrollBar}" />
                </Trigger>
            </Style.Triggers>
        </Style>

        <!– Style for overall  ScrollViewer >
        <Style x:Key="FavsScrollViewer" TargetType="{x:Type ScrollViewer}">
            <Setter Property="OverridesDefaultStyle" Value="True"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type ScrollViewer}">
                        <Grid>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="Auto"/>
                                <ColumnDefinition/>
                            </Grid.ColumnDefinitions>
                            <Grid.RowDefinitions>
                                <RowDefinition/>
                                <RowDefinition Height="Auto"/>
                            </Grid.RowDefinitions>

                            <ScrollContentPresenter Grid.Column="1″/>

                            <ScrollBar Name="PART_VerticalScrollBar"
            Value="{TemplateBinding VerticalOffset}"
            Maximum="{TemplateBinding ScrollableHeight}"
            ViewportSize="{TemplateBinding ViewportHeight}"
            Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}"/>
                            <ScrollBar Name="PART_HorizontalScrollBar"
            Orientation="Horizontal"
            Grid.Row="1″
            Grid.Column="1″
            Value="{TemplateBinding HorizontalOffset}"
            Maximum="{TemplateBinding ScrollableWidth}"
            ViewportSize="{TemplateBinding ViewportWidth}"
            Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}"/>

                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

  </Window.Resources>

    <Grid x:Name="LayoutRoot">
        <ScrollViewer     RenderTransformOrigin="0.5,0.5″ HorizontalAlignment="Stretch"
                        Margin="0,0,0,0″
                        Width="Auto" HorizontalScrollBarVisibility="Visible"
                        Style="{StaticResource FavsScrollViewer}">
         </ScrollViewer>
    </Grid>
</Window>

And if you want to try this for yourself, here is a VS 2008 demo project.

License

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


Written By
Software Developer (Senior)
United Kingdom United Kingdom
I currently hold the following qualifications (amongst others, I also studied Music Technology and Electronics, for my sins)

- MSc (Passed with distinctions), in Information Technology for E-Commerce
- BSc Hons (1st class) in Computer Science & Artificial Intelligence

Both of these at Sussex University UK.

Award(s)

I am lucky enough to have won a few awards for Zany Crazy code articles over the years

  • Microsoft C# MVP 2016
  • Codeproject MVP 2016
  • Microsoft C# MVP 2015
  • Codeproject MVP 2015
  • Microsoft C# MVP 2014
  • Codeproject MVP 2014
  • Microsoft C# MVP 2013
  • Codeproject MVP 2013
  • Microsoft C# MVP 2012
  • Codeproject MVP 2012
  • Microsoft C# MVP 2011
  • Codeproject MVP 2011
  • Microsoft C# MVP 2010
  • Codeproject MVP 2010
  • Microsoft C# MVP 2009
  • Codeproject MVP 2009
  • Microsoft C# MVP 2008
  • Codeproject MVP 2008
  • And numerous codeproject awards which you can see over at my blog

Comments and Discussions

 
Questionhow to ennable the scrollbar Pin
lapis balazs22-Aug-10 9:25
lapis balazs22-Aug-10 9:25 
Questionhow to make vertical scrollbar to the right hand-side of the screen? Pin
Member 404502226-Nov-09 23:08
Member 404502226-Nov-09 23:08 
AnswerRe: how to make vertical scrollbar to the right hand-side of the screen? Pin
Sacha Barber26-Nov-09 23:27
Sacha Barber26-Nov-09 23:27 
AnswerRe: how to make vertical scrollbar to the right hand-side of the screen? Pin
Ovidiu Carstea16-Nov-11 4:10
Ovidiu Carstea16-Nov-11 4:10 
GeneralRe: how to make vertical scrollbar to the right hand-side of the screen? Pin
Sacha Barber16-Nov-11 9:37
Sacha Barber16-Nov-11 9:37 
QuestionHow to display the scrollviewer/scrollbar only when needs to scroll? Pin
Viji Raj16-Oct-09 9:17
Viji Raj16-Oct-09 9:17 
AnswerRe: How to display the scrollviewer/scrollbar only when needs to scroll? Pin
Sacha Barber16-Oct-09 17:50
Sacha Barber16-Oct-09 17:50 
GeneralRe: How to display the scrollviewer/scrollbar only when needs to scroll? Pin
Viji Raj16-Oct-09 19:18
Viji Raj16-Oct-09 19:18 

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.