How would I go about changing these properties programmatically?
Controls can have multiple states like Disabled, Mouse Over or Pressed which all have different visual representations. Have a look at the style and template documentation for ScollBar
.
You can in theory get the ScrollBar
of a ListBox
in code by searching all children like this:
In your code you can get the ScrollBar
and apply a different color to it, but this will not work for all the different states. Of course you could create a custom style to handle all states and assign it here, too.
<ListBox x:Name="MyListBox" ... />
var scrollbar = FindChild<ScrollBar>(MyListBox, null);
scrollbar.Background = Brushes.Red;
scrollbar.Foreground = Brushes.Blue;
However, I do not recommend using code here. Instead you could extract the default style and control template of ScrollBar
using Blend or Visual Studio. In this copy of the style, you could change the default colors to your needs (look for SolidColorBrush
es in the code below). Then create a ListBox
style based on the default style and add the implict styles of the ScrollBar
to its Resources
section. That is it, the styles for the ScrollBar
will be applied automatically to the ListBox
scrollbar.
If you do not want the ListBox
style to be applied to all ListBox
es in scope, add an x:Key
to make it explicit and reference it manually using StaticResource
or DynamicResource
.
<Style TargetType="{x:Type ListBox}"
BasedOn="{StaticResource {x:Type ListBox}}">
<Style.Resources>
<Style x:Key="FocusVisual">
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate>
<Rectangle Margin="2"
StrokeDashArray="1 2"
SnapsToDevicePixels="true"
StrokeThickness="1"
Stroke="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<SolidColorBrush x:Key="ScrollBar.Static.Background"
Color="#F0F0F0" />
<SolidColorBrush x:Key="ScrollBar.Static.Border"
Color="#F0F0F0" />
<SolidColorBrush x:Key="ScrollBar.Static.Glyph"
Color="#606060" />
<SolidColorBrush x:Key="ScrollBar.Static.Thumb"
Color="#CDCDCD" />
<SolidColorBrush x:Key="ScrollBar.MouseOver.Background"
Color="#DADADA" />
<SolidColorBrush x:Key="ScrollBar.MouseOver.Border"
Color="#DADADA" />
<SolidColorBrush x:Key="ScrollBar.MouseOver.Glyph"
Color="#000000" />
<SolidColorBrush x:Key="ScrollBar.MouseOver.Thumb"
Color="#A6A6A6" />
<SolidColorBrush x:Key="ScrollBar.Pressed.Background"
Color="#606060" />
<SolidColorBrush x:Key="ScrollBar.Pressed.Border"
Color="#606060" />
<SolidColorBrush x:Key="ScrollBar.Pressed.Thumb"
Color="#606060" />
<SolidColorBrush x:Key="ScrollBar.Pressed.Glyph"
Color="#FFFFFF" />
<SolidColorBrush x:Key="ScrollBar.Disabled.Background"
Color="#F0F0F0" />
<SolidColorBrush x:Key="ScrollBar.Disabled.Border"
Color="#F0F0F0" />
<SolidColorBrush x:Key="ScrollBar.Disabled.Glyph"
Color="#BFBFBF" />
<Style x:Key="RepeatButtonTransparent"
TargetType="{x:Type RepeatButton}">
<Setter Property="OverridesDefaultStyle"
Value="true" />
<Setter Property="Background"
Value="Transparent" />
<Setter Property="Focusable"
Value="false" />
<Setter Property="IsTabStop"
Value="false" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type RepeatButton}">
<Rectangle Fill="{TemplateBinding Background}"
Height="{TemplateBinding Height}"
Width="{TemplateBinding Width}" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="ScrollBarButton"
TargetType="{x:Type RepeatButton}">
<Setter Property="FocusVisualStyle"
Value="{StaticResource FocusVisual}" />
<Setter Property="BorderThickness"
Value="1" />
<Setter Property="HorizontalContentAlignment"
Value="Center" />
<Setter Property="VerticalContentAlignment"
Value="Center" />
<Setter Property="Padding"
Value="1" />
<Setter Property="Focusable"
Value="false" />
<Setter Property="IsTabStop"
Value="false" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type RepeatButton}">
<Border x:Name="border"
Background="{StaticResource ScrollBar.Static.Background}"
BorderThickness="1"
BorderBrush="{StaticResource ScrollBar.Static.Border}"
SnapsToDevicePixels="true">
<ContentPresenter x:Name="contentPresenter"
Focusable="False"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
Margin="{TemplateBinding Padding}"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver"
Value="true">
<Setter Property="Background"
TargetName="border"
Value="{StaticResource ScrollBar.MouseOver.Background}" />
<Setter Property="BorderBrush"
TargetName="border"
Value="{StaticResource ScrollBar.MouseOver.Border}" />
</Trigger>
<Trigger Property="IsPressed"
Value="true">
<Setter Property="Background"
TargetName="border"
Value="{StaticResource ScrollBar.Pressed.Background}" />
<Setter Property="BorderBrush"
TargetName="border"
Value="{StaticResource ScrollBar.Pressed.Border}" />
</Trigger>
<Trigger Property="IsEnabled"
Value="false">
<Setter Property="Opacity"
TargetName="contentPresenter"
Value="0.56" />
<Setter Property="Background"
TargetName="border"
Value="{StaticResource ScrollBar.Disabled.Background}" />
<Setter Property="BorderBrush"
TargetName="border"
Value="{StaticResource ScrollBar.Disabled.Border}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="ScrollBarThumbVertical"
TargetType="{x:Type Thumb}">
<Setter Property="OverridesDefaultStyle"
Value="true" />
<Setter Property="IsTabStop"
Value="false" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Thumb}">
<Rectangle x:Name="rectangle"
Fill="{StaticResource ScrollBar.Static.Thumb}"
Height="{TemplateBinding Height}"
SnapsToDevicePixels="True"
Width="{TemplateBinding Width}" />
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver"
Value="true">
<Setter Property="Fill"
TargetName="rectangle"
Value="{StaticResource ScrollBar.MouseOver.Thumb}" />
</Trigger>
<Trigger Property="IsDragging"
Value="true">
<Setter Property="Fill"
TargetName="rectangle"
Value="{StaticResource ScrollBar.Pressed.Thumb}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="ScrollBarThumbHorizontal"
TargetType="{x:Type Thumb}">
<Setter Property="OverridesDefaultStyle"
Value="true" />
<Setter Property="IsTabStop"
Value="false" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Thumb}">
<Rectangle x:Name="rectangle"
Fill="{StaticResource ScrollBar.Static.Thumb}"
Height="{TemplateBinding Height}"
SnapsToDevicePixels="True"
Width="{TemplateBinding Width}" />
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver"
Value="true">
<Setter Property="Fill"
TargetName="rectangle"
Value="{StaticResource ScrollBar.MouseOver.Thumb}" />
</Trigger>
<Trigger Property="IsDragging"
Value="true">
<Setter Property="Fill"
TargetName="rectangle"
Value="{StaticResource ScrollBar.Pressed.Thumb}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type ScrollBar}">
<Setter Property="Stylus.IsPressAndHoldEnabled"
Value="false" />
<Setter Property="Stylus.IsFlicksEnabled"
Value="false" />
<Setter Property="Background"
Value="{StaticResource ScrollBar.Static.Background}" />
<Setter Property="BorderBrush"
Value="{StaticResource ScrollBar.Static.Border}" />
<Setter Property="Foreground"
Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" />
<Setter Property="BorderThickness"
Value="1,0" />
<Setter Property="Width"
Value="{DynamicResource {x:Static SystemParameters.VerticalScrollBarWidthKey}}" />
<Setter Property="MinWidth"
Value="{DynamicResource {x:Static SystemParameters.VerticalScrollBarWidthKey}}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ScrollBar}">
<Grid x:Name="Bg"
SnapsToDevicePixels="true">
<Grid.RowDefinitions>
<RowDefinition MaxHeight="{DynamicResource {x:Static SystemParameters.VerticalScrollBarButtonHeightKey}}" />
<RowDefinition Height="0.00001*" />
<RowDefinition MaxHeight="{DynamicResource {x:Static SystemParameters.VerticalScrollBarButtonHeightKey}}" />
</Grid.RowDefinitions>
<Border Background="{TemplateBinding Background}"
BorderThickness="{TemplateBinding BorderThickness}"
BorderBrush="{TemplateBinding BorderBrush}"
Grid.Row="1" />
<RepeatButton x:Name="PART_LineUpButton"
Command="{x:Static ScrollBar.LineUpCommand}"
IsEnabled="{TemplateBinding IsMouseOver}"
Style="{StaticResource ScrollBarButton}">
<Path x:Name="ArrowTop"
Data="M 0,4 C0,4 0,6 0,6 0,6 3.5,2.5 3.5,2.5 3.5,2.5 7,6 7,6 7,6 7,4 7,4 7,4 3.5,0.5 3.5,0.5 3.5,0.5 0,4 0,4 z"
Fill="{StaticResource ScrollBar.Static.Glyph}"
Margin="3,4,3,3"
Stretch="Uniform" />
</RepeatButton>
<Track x:Name="PART_Track"
IsEnabled="{TemplateBinding IsMouseOver}"
IsDirectionReversed="true"
Grid.Row="1">
<Track.DecreaseRepeatButton>
<RepeatButton Command="{x:Static ScrollBar.PageUpCommand}"
Style="{StaticResource RepeatButtonTransparent}" />
</Track.DecreaseRepeatButton>
<Track.IncreaseRepeatButton>
<RepeatButton Command="{x:Static ScrollBar.PageDownCommand}"
Style="{StaticResource RepeatButtonTransparent}" />
</Track.IncreaseRepeatButton>
<Track.Thumb>
<Thumb Style="{StaticResource ScrollBarThumbVertical}" />
</Track.Thumb>
</Track>
<RepeatButton x:Name="PART_LineDownButton"
Command="{x:Static ScrollBar.LineDownCommand}"
IsEnabled="{TemplateBinding IsMouseOver}"
Grid.Row="2"
Style="{StaticResource ScrollBarButton}">
<Path x:Name="ArrowBottom"
Data="M 0,2.5 C0,2.5 0,0.5 0,0.5 0,0.5 3.5,4 3.5,4 3.5,4 7,0.5 7,0.5 7,0.5 7,2.5 7,2.5 7,2.5 3.5,6 3.5,6 3.5,6 0,2.5 0,2.5 z"
Fill="{StaticResource ScrollBar.Static.Glyph}"
Margin="3,4,3,3"
Stretch="Uniform" />
</RepeatButton>
</Grid>
<ControlTemplate.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding IsMouseOver, ElementName=PART_LineDownButton}"
Value="true" />
<Condition Binding="{Binding IsPressed, ElementName=PART_LineDownButton}"
Value="true" />
</MultiDataTrigger.Conditions>
<Setter Property="Fill"
TargetName="ArrowBottom"
Value="{StaticResource ScrollBar.Pressed.Glyph}" />
</MultiDataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding IsMouseOver, ElementName=PART_LineUpButton}"
Value="true" />
<Condition Binding="{Binding IsPressed, ElementName=PART_LineUpButton}"
Value="true" />
</MultiDataTrigger.Conditions>
<Setter Property="Fill"
TargetName="ArrowTop"
Value="{StaticResource ScrollBar.Pressed.Glyph}" />
</MultiDataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding IsMouseOver, ElementName=PART_LineDownButton}"
Value="true" />
<Condition Binding="{Binding IsPressed, ElementName=PART_LineDownButton}"
Value="false" />
</MultiDataTrigger.Conditions>
<Setter Property="Fill"
TargetName="ArrowBottom"
Value="{StaticResource ScrollBar.MouseOver.Glyph}" />
</MultiDataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding IsMouseOver, ElementName=PART_LineUpButton}"
Value="true" />
<Condition Binding="{Binding IsPressed, ElementName=PART_LineUpButton}"
Value="false" />
</MultiDataTrigger.Conditions>
<Setter Property="Fill"
TargetName="ArrowTop"
Value="{StaticResource ScrollBar.MouseOver.Glyph}" />
</MultiDataTrigger>
<Trigger Property="IsEnabled"
Value="false">
<Setter Property="Fill"
TargetName="ArrowTop"
Value="{StaticResource ScrollBar.Disabled.Glyph}" />
<Setter Property="Fill"
TargetName="ArrowBottom"
Value="{StaticResource ScrollBar.Disabled.Glyph}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="Orientation"
Value="Horizontal">
<Setter Property="Width"
Value="Auto" />
<Setter Property="MinWidth"
Value="0" />
<Setter Property="Height"
Value="{DynamicResource {x:Static SystemParameters.HorizontalScrollBarHeightKey}}" />
<Setter Property="MinHeight"
Value="{DynamicResource {x:Static SystemParameters.HorizontalScrollBarHeightKey}}" />
<Setter Property="BorderThickness"
Value="0,1" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ScrollBar}">
<Grid x:Name="Bg"
SnapsToDevicePixels="true">
<Grid.ColumnDefinitions>
<ColumnDefinition MaxWidth="{DynamicResource {x:Static SystemParameters.HorizontalScrollBarButtonWidthKey}}" />
<ColumnDefinition Width="0.00001*" />
<ColumnDefinition MaxWidth="{DynamicResource {x:Static SystemParameters.HorizontalScrollBarButtonWidthKey}}" />
</Grid.ColumnDefinitions>
<Border Background="{TemplateBinding Background}"
BorderThickness="{TemplateBinding BorderThickness}"
BorderBrush="{TemplateBinding BorderBrush}"
Grid.Column="1" />
<RepeatButton x:Name="PART_LineLeftButton"
Command="{x:Static ScrollBar.LineLeftCommand}"
IsEnabled="{TemplateBinding IsMouseOver}"
Style="{StaticResource ScrollBarButton}">
<Path x:Name="ArrowLeft"
Data="M 3.18,7 C3.18,7 5,7 5,7 5,7 1.81,3.5 1.81,3.5 1.81,3.5 5,0 5,0 5,0 3.18,0 3.18,0 3.18,0 0,3.5 0,3.5 0,3.5 3.18,7 3.18,7 z"
Fill="{StaticResource ScrollBar.Static.Glyph}"
Margin="3"
Stretch="Uniform" />
</RepeatButton>
<Track x:Name="PART_Track"
Grid.Column="1"
IsEnabled="{TemplateBinding IsMouseOver}">
<Track.DecreaseRepeatButton>
<RepeatButton Command="{x:Static ScrollBar.PageLeftCommand}"
Style="{StaticResource RepeatButtonTransparent}" />
</Track.DecreaseRepeatButton>
<Track.IncreaseRepeatButton>
<RepeatButton Command="{x:Static ScrollBar.PageRightCommand}"
Style="{StaticResource RepeatButtonTransparent}" />
</Track.IncreaseRepeatButton>
<Track.Thumb>
<Thumb Style="{StaticResource ScrollBarThumbHorizontal}" />
</Track.Thumb>
</Track>
<RepeatButton x:Name="PART_LineRightButton"
Command="{x:Static ScrollBar.LineRightCommand}"
Grid.Column="2"
IsEnabled="{TemplateBinding IsMouseOver}"
Style="{StaticResource ScrollBarButton}">
<Path x:Name="ArrowRight"
Data="M 1.81,7 C1.81,7 0,7 0,7 0,7 3.18,3.5 3.18,3.5 3.18,3.5 0,0 0,0 0,0 1.81,0 1.81,0 1.81,0 5,3.5 5,3.5 5,3.5 1.81,7 1.81,7 z"
Fill="{StaticResource ScrollBar.Static.Glyph}"
Margin="3"
Stretch="Uniform" />
</RepeatButton>
</Grid>
<ControlTemplate.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding IsMouseOver, ElementName=PART_LineRightButton}"
Value="true" />
<Condition Binding="{Binding IsPressed, ElementName=PART_LineRightButton}"
Value="true" />
</MultiDataTrigger.Conditions>
<Setter Property="Fill"
TargetName="ArrowRight"
Value="{StaticResource ScrollBar.Pressed.Glyph}" />
</MultiDataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding IsMouseOver, ElementName=PART_LineLeftButton}"
Value="true" />
<Condition Binding="{Binding IsPressed, ElementName=PART_LineLeftButton}"
Value="true" />
</MultiDataTrigger.Conditions>
<Setter Property="Fill"
TargetName="ArrowLeft"
Value="{StaticResource ScrollBar.Pressed.Glyph}" />
</MultiDataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding IsMouseOver, ElementName=PART_LineRightButton}"
Value="true" />
<Condition Binding="{Binding IsPressed, ElementName=PART_LineRightButton}"
Value="false" />
</MultiDataTrigger.Conditions>
<Setter Property="Fill"
TargetName="ArrowRight"
Value="{StaticResource ScrollBar.MouseOver.Glyph}" />
</MultiDataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding IsMouseOver, ElementName=PART_LineLeftButton}"
Value="true" />
<Condition Binding="{Binding IsPressed, ElementName=PART_LineLeftButton}"
Value="false" />
</MultiDataTrigger.Conditions>
<Setter Property="Fill"
TargetName="ArrowLeft"
Value="{StaticResource ScrollBar.MouseOver.Glyph}" />
</MultiDataTrigger>
<Trigger Property="IsEnabled"
Value="false">
<Setter Property="Fill"
TargetName="ArrowLeft"
Value="{StaticResource ScrollBar.Disabled.Glyph}" />
<Setter Property="Fill"
TargetName="ArrowRight"
Value="{StaticResource ScrollBar.Disabled.Glyph}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
</Style.Resources>
</Style>
If there are (for whatever reason) nested scrollbars in the ListBox
, the styles would be applied there, too, since they are implicit. If you run into an issue there, extract the full ListBox
style and create an explicit style for the contained ScrollViewer
that you can customize the same way.
Also how about in another window and with the ability to alter them at runtime? I've tried numerous approaches using FindResource and Resources.FindName [...]
In order to change resources or themes at runtime, you could add the resources in question to a ResourceDicitonary
and add it to the applicaiton resource dictionary (in App.xaml
). You have to reference the resources using DynamicResource
, otherwise they will not be updated when the resources are replaced. Then at runtime you can relace a resource dictionary with another to change styles. See these related questions and answers.