WPF: Transparent Scrollbars in the ScrollView

A Visual Studio 2008 Solution with the complete code listing for this posting is attached.

Through the use of ControlTemplates we are able to customise the look and feel of all WPF controls. Here I will demonstrate using a ControlTemplate to make the ScrollBars of the ScrollViewer draw on top of the content it is scrolling rather than beside and below the content. Making the ScrollBars semi-transparent allows the content below to be seen through the ScrollBars.

Before we begin, you should familiarise yourself with the ScrollViewer Control Template example from the MSDN as the solution presented here is based on it.

The default ContentTemplate for the ScrollViewer creates a 2x2 grid and inserts the following child controls at the specified (row, column) locations:

  • (0, 0) - a ScrollContentPresenter. This class draws, scrolls and clips the ScrollViewers logical child.
  • (0, 1) - a ScrollBar. This is the vertical scrollbar.
  • (1, 0) - a ScrollBar. This is the horizontal scrollbar.

This gives us the usual layout of a scrolled view where the scrollbars are docked to the right and bottom of the content being scrolled.

To get the desired effect of having semi-transparent scrollbars on top of the content we make the following changes to the default ContentTemplate:

  • Make the ScrollContentPresenter have a RowSpan and ColumnSpan of two. This will make the content take up the entire width and height of the grid.
  • Adjust the Opacity of each ScrollBar so we can see the content through the ScrollBar
  • We must add the ScrollContentPresenter to the grid before the ScrollBars to get the correct z-Ordering - we want the ScrollContentPresenter to be under the ScrollBars.

The new style, which sets our ContentTemplate, is shown below:"

  1. <Style x:Key="myStyle" TargetType="{x:Type ScrollViewer}">
  2. <Setter Property="OverridesDefaultStyle" Value="True" />
  3. <Setter Property="Template">
  4. <Setter.Value>
  5. <ControlTemplate TargetType="{x:Type ScrollViewer}">
  6. <Grid>
  7. <Grid.ColumnDefinitions>
  8. <ColumnDefinition Width="*" />
  9. <ColumnDefinition Width="Auto" />
  10. </Grid.ColumnDefinitions>
  11. <Grid.RowDefinitions>
  12. <RowDefinition Height="*"/>
  13. <RowDefinition Height="Auto"/>
  14. </Grid.RowDefinitions>
  15. <ScrollContentPresenter Grid.ColumnSpan="2" Grid.RowSpan="2"/>
  16. <ScrollBar
  17. Name="PART_VerticalScrollBar"
  18. Opacity="0.75"
  19. Grid.Column="1"
  20. Value="{TemplateBinding VerticalOffset}"
  21. Maximum="{TemplateBinding ScrollableHeight}"
  22. ViewportSize="{TemplateBinding ViewportHeight}"
  23. Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}" />
  24. <ScrollBar
  25. Name="PART_HorizontalScrollBar"
  26. Orientation="Horizontal"
  27. Opacity="0.75"
  28. Grid.Row="1"
  29. Value="{TemplateBinding HorizontalOffset}"
  30. Maximum="{TemplateBinding ScrollableWidth}"
  31. ViewportSize="{TemplateBinding ViewportWidth}"
  32. Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}" />
  33. </Grid>
  34. </ControlTemplate>
  35. </Setter.Value>
  36. </Setter>
  37. </Style>

We can create some content to scroll such as the following:

  1. <ScrollViewer HorizontalScrollBarVisibility="Auto" Style="{StaticResource myStyle}" >
  2. <StackPanel>
  3. <TextBlock FontSize="64">Scroll Me! Scroll Me! Scroll Me!</TextBlock>
  4. <TextBlock FontSize="64">Scroll Me! Scroll Me! Scroll Me!</TextBlock>
  5. <TextBlock FontSize="64">Scroll Me! Scroll Me! Scroll Me!</TextBlock>
  6. <TextBlock FontSize="64">Scroll Me! Scroll Me! Scroll Me!</TextBlock>
  7. <TextBlock FontSize="64">Scroll Me! Scroll Me! Scroll Me!</TextBlock>
  8. <TextBlock FontSize="64">Scroll Me! Scroll Me! Scroll Me!</TextBlock>
  9. </StackPanel>
  10. </ScrollViewer>

This results in the following window. Notice how you can see the content through the ScrollBars. The content also draws in the little square in the bottom-right corner of the grid:

Default ScrollViewer Styled ScrollViewer with semi-transparent ScrollBars

It may be desirable to make the ScrollBars more opaque when the mouse is over the scrollbar. This will make it easier for the user to see the ScrollBar parts when they are interacting with it and also easier to see through the ScrollBar when not interacting with it.

We can achieve this by styling the scrollbar:

  1. <Style x:Key="myScrollBarStyle" TargetType="{x:Type ScrollBar}">
  2. <Style.Triggers>
  3. <Trigger Property="IsMouseOver" Value="True">
  4. <Setter Property="Opacity" Value="0.9" />
  5. </Trigger>
  6. <Trigger Property="IsMouseOver" Value="False">
  7. <Setter Property="Opacity" Value="0.4" />
  8. </Trigger>
  9. </Style.Triggers>
  10. </Style>
  12. <Style x:Key="myStyle" TargetType="{x:Type ScrollViewer}">
  13. <Setter Property="OverridesDefaultStyle" Value="True" />
  14. <Setter Property="Template">
  15. <Setter.Value>
  16. <ControlTemplate TargetType="{x:Type ScrollViewer}">
  17. <Grid>
  18. <Grid.ColumnDefinitions>
  19. <ColumnDefinition Width="*" />
  20. <ColumnDefinition Width="Auto" />
  21. </Grid.ColumnDefinitions>
  22. <Grid.RowDefinitions>
  23. <RowDefinition Height="*"/>
  24. <RowDefinition Height="Auto"/>
  25. </Grid.RowDefinitions>
  26. <ScrollContentPresenter Grid.ColumnSpan="2" Grid.RowSpan="2"/>
  27. <ScrollBar
  28. Style="{StaticResource myScrollBarStyle}"
  29. Name="PART_VerticalScrollBar"
  30. Grid.Column="1"
  31. Value="{TemplateBinding VerticalOffset}"
  32. Maximum="{TemplateBinding ScrollableHeight}"
  33. ViewportSize="{TemplateBinding ViewportHeight}"
  34. Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}" />
  35. <ScrollBar
  36. Style="{StaticResource myScrollBarStyle}"
  37. Name="PART_HorizontalScrollBar"
  38. Orientation="Horizontal"
  39. Grid.Row="1"
  40. Value="{TemplateBinding HorizontalOffset}"
  41. Maximum="{TemplateBinding ScrollableWidth}"
  42. ViewportSize="{TemplateBinding ViewportWidth}"
  43. Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}" />
  44. </Grid>
  45. </ControlTemplate>
  46. </Setter.Value>
  47. </Setter>
  48. </Style>

The result of this styling is shown below. Notice that the vertical ScrollBar (which has the mouse over it) is more opaque than the horizontal ScrollBar:


Hi, thanks again for the sample!

Just one thing:

The default scrollviewer has a small rectangle in the bottom right area and it looks better if you add this in your template as well:

  1. <Rectangle
  2. Fill="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"
  3. Opacity="0.4"
  4. Grid.Column="1"
  5. Grid.Row="1"/>

cheers from Brisbane

Hi Patrick,

Agreed that the little corner piece is a little naff as seen in my screen shots. A nice little filler like that would do the trick!

Thanks - and cheers from Perth!