如何以编程方式更改 ListBox ScrollBar 的 ScrollBar Foreground/Background 属性?

How to programmatically change ScrollBar Foreground/Background properties of a ListBox ScrollBar?

我终于从 winforms 切换到 WPF,尽管我什至很少使用 winforms。在 Main Window 中添加了一个 ListBox 控件和此 XAML 代码以更改其 ScrollBar Foreground/Background.[=18 的颜色=]

<ListBox.Resources>
    <Style x:Key="ScrollBarColor" TargetType="ScrollBar">
        <Setter Property="Background" Value="#FF343434" />
        <Setter Property="Foreground" Value="#FF8E9195" />
    </Style>
</ListBox.Resources>

我将如何以编程方式更改这些属性?另外,在另一个 window 中并且能够在运行时更改它们怎么样?我已经尝试了很多使用 FindResourceResources.FindName 的方法,使用密钥作为 arg 但到目前为止没有运气。如果方向正确,我们将不胜感激。

在 WinForms 中执行此操作对我来说会更耗时且更熟悉,但我正在尝试进行转换。

How would I go about changing these properties programmatically?

控件可以有多个状态,例如 DisabledMouse OverPressed,它们都有不同的视觉表现。查看 ScollBar.

的样式和模板文档

理论上,您可以像这样搜索所有子项,从而在代码中获得 ListBoxScrollBar

  • How can I find WPF controls by name or type?

在您的代码中,您可以获得 ScrollBar 并为其应用不同的颜色,但这不适用于所有不同的状态。当然,您也可以创建自定义样式来处理所有状态并将其分配到此处。

<ListBox x:Name="MyListBox" ... />
var scrollbar = FindChild<ScrollBar>(MyListBox, null);
scrollbar.Background = Brushes.Red;
scrollbar.Foreground = Brushes.Blue;

但是,我不推荐使用这里的代码。相反,您可以使用 Blend 或 Visual Studio extract the default style and control template of ScrollBar。在此样式副本中,您可以根据需要更改默认颜色(在下面的代码中查找 SolidColorBrushes)。然后在默认样式的基础上创建一个ListBox样式,并将ScrollBar隐式样式添加到它的Resources部分。也就是说,ScrollBar 的样式将自动应用到 ListBox 滚动条。

如果您不希望将 ListBox 样式应用到范围内的所有 ListBoxes,添加一个 x:Key 使其明确并使用 [=27 手动引用它=] 或 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>

如果 ListBox 中有(无论出于何种原因)嵌套滚动条,样式也将应用到那里,因为它们是隐式的。如果您 运行 在那里遇到问题,请提取 full ListBox 样式并为包含的 ScrollViewer 创建一个显式样式,您可以自定义相同的样式方式。

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 [...]

为了在 运行 时更改资源或主题,您可以将有问题的资源添加到 ResourceDicitonary 并将其添加到应用程序资源字典(在 App.xaml 中) .您必须使用 DynamicResource 引用资源,否则资源被替换时不会更新。然后在 运行 时,您可以将资源字典替换为另一个以更改样式。查看这些相关问题和答案。

  • WPF: Changing Resources (colors) from the App.xaml during runtime
  • Change theme at runtime