如何让WPF ScrollViewer的滚动条变样式?

摘要:该 XAML 代码是一个 WPF 资源字典(ResourceDictionary),核心作用是自定义 ScrollViewer(滚动视图)和 ScrollBar(滚动条)的外观与交互行为,通过样式覆盖默认控件样式,实现统一、个性化的滚动交互
该 XAML 代码是一个 WPF 资源字典(ResourceDictionary),核心作用是自定义 ScrollViewer(滚动视图)和 ScrollBar(滚动条)的外观与交互行为,通过样式覆盖默认控件样式,实现统一、个性化的滚动交互效果,无需在每个使用控件的地方重复定义样式,可直接在项目中引用。 基础外观: 边框透明(BorderThickness=0,取消默认边框) 内部网格布局:包含 “滚动内容区” 和 “垂直 / 水平滚动条” 模板结构(ControlTemplate): 外层边框(Border):承载滚动视图的整体容器 内部网格(Grid): 1) 滚动的内容(ScrollContentPresenter):显示滚动的内容(绑定 Cursor、Padding 等属性) 2) 垂直滚动条(PART_VerticalScrollBar):右对齐,绑定 for_scrollbar 样式,可见性由内容高度决定(ComputedVerticalScrollBarVisibility) 3) 水平滚动条(PART_HorizontalScrollBar):底对齐,同上,可见性由内容宽度决定 交互动画(通过 EventTrigger 实现): 是该样式的核心亮点,实现 “滚动时 / 鼠标 hover 时” 的动态透明度变化,提升交互体验: 触发事件 动画效果 细节 ScrollChanged(滚动时) 滚动条透明度 “0.2→0.8→0.2” - 先 1 秒内从 0.2 升到 0.8(突出滚动条) - 再 1 秒内从 0.8 降回 0.2(滚动停止后恢复低调) MouseEnter(鼠标移入滚动条) 透明度 0.2→0.8(0.7 秒过渡) 鼠标靠近时,滚动条变清晰,便于操作 MouseLeave(鼠标移出滚动条) 透明度 0.8→0.2(0.7 秒过渡) 鼠标离开后,滚动条恢复半透明,减少视觉干扰 添加资源字典 ScrollViewerStyle.xaml 点击查看代码 <ResourceDictionary xmlns="<http://schemas.microsoft.com/winfx/2006/xaml/presentation>" xmlns:x="<http://schemas.microsoft.com/winfx/2006/xaml>"> <!-- ScrollViewer 滚动条 --> <Style x:Key="ScrollBarThumb" TargetType="{x:Type Thumb}"> <Setter Property="OverridesDefaultStyle" Value="true"/> <Setter Property="IsTabStop" Value="false"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type Thumb}"> <Grid> <!--滚动条颜色--> <Border Background="#646465" CornerRadius="3"/> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style> <Style x:Key="HorizontalScrollBarPageButton" 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="Opacity" Value="0.2"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type RepeatButton}"> <Rectangle Fill="{TemplateBinding Background}" Width="{TemplateBinding Width}" Height="{TemplateBinding Height}"/> </ControlTemplate> </Setter.Value> </Setter> </Style> <Style x:Key="VerticalScrollBarPageButton" 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="Opacity" Value="0.2"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type RepeatButton}"> <Rectangle Fill="{TemplateBinding Background}" Width="{TemplateBinding Width}" Height="{TemplateBinding Height}"/> </ControlTemplate> </Setter.Value> </Setter> </Style> <!--滚动条上下按钮--> <Style x:Key="VerticalScrollBarPageButton2" 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="Opacity" Value="0"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type RepeatButton}"> <Rectangle Fill="#90000000" Width="0" Height="0"/> </ControlTemplate> </Setter.Value> </Setter> </Style> <Style x:Key="for_scrollbar" TargetType="{x:Type ScrollBar}"> <Setter Property="Stylus.IsPressAndHoldEnabled" Value="false"/> <Setter Property="Stylus.IsFlicksEnabled" Value="false"/> <Setter Property="Background" Value="Transparent"/> <Setter Property="Margin" Value="0,1,1,6"/> <Setter Property="Width" Value="10"/> <Setter Property="MinWidth" Value="5"/> <Setter Property="Opacity" Value="0.2"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type ScrollBar}"> <Grid x:Name="Bg" SnapsToDevicePixels="true"> <Grid.RowDefinitions> <RowDefinition Height="auto"></RowDefinition> <RowDefinition Height="*"></RowDefinition> <RowDefinition Height="auto"></RowDefinition> </Grid.RowDefinitions> <RepeatButton Grid.Row="0" Style="{StaticResource VerticalScrollBarPageButton2}" Command="{x:Static ScrollBar.PageUpCommand}"/> <Track x:Name="PART_Track" Grid.Row="1" IsEnabled="{TemplateBinding IsMouseOver}" IsDirectionReversed="true"> <Track.DecreaseRepeatButton> <RepeatButton Style="{StaticResource VerticalScrollBarPageButton}" Command="{x:Static ScrollBar.PageUpCommand}"/> </Track.DecreaseRepeatButton> <Track.IncreaseRepeatButton> <RepeatButton Style="{StaticResource VerticalScrollBarPageButton}" Command="{x:Static ScrollBar.PageDownCommand}"/> </Track.IncreaseRepeatButton> <Track.Thumb> <Thumb Style="{StaticResource ScrollBarThumb}"/> </Track.Thumb> </Track> <RepeatButton Grid.Row="2" Style="{StaticResource VerticalScrollBarPageButton2}" Command="{x:Static ScrollBar.PageDownCommand}"/> </Grid> </ControlTemplate> </Setter.Value> </Setter> <Style.Triggers> <Trigger Property="Orientation" Value="Horizontal"> <Setter Property="Background" Value="Transparent"/> <Setter Property="Margin" Value="1,0,6,1"/> <Setter Property="Height" Value="5"/> <Setter Property="MinHeight" Value="5"/> <Setter Property="Width" Value="Auto"/> <Setter Property="Opacity" Value="0.2"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type ScrollBar}"> <Grid x:Name="Bg" SnapsToDevicePixels="true"> <Track x:Name="PART_Track" IsEnabled="{TemplateBinding IsMouseOver}"> <Track.DecreaseRepeatButton> <RepeatButton Style="{StaticResource HorizontalScrollBarPageButton}" Command="{x:Static ScrollBar.PageLeftCommand}"/> </Track.DecreaseRepeatButton> <Track.IncreaseRepeatButton> <RepeatButton Style="{StaticResource HorizontalScrollBarPageButton}" Command="{x:Static ScrollBar.PageRightCommand}"/> </Track.IncreaseRepeatButton> <Track.Thumb> <Thumb Style="{StaticResource ScrollBarThumb}"/> </Track.Thumb> </Track> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Trigger> </Style.Triggers> </Style> <Style x:Key="for_scrollviewer" TargetType="{x:Type ScrollViewer}"> <Setter Property="BorderBrush" Value="LightGray"/> <Setter Property="BorderThickness" Value="0"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type ScrollViewer}"> <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" SnapsToDevicePixels="True"> <Grid Background="{TemplateBinding Background}"> <ScrollContentPresenter Cursor="{TemplateBinding Cursor}" Margin="{TemplateBinding Padding}" ContentTemplate="{TemplateBinding ContentTemplate}"/> <ScrollBar x:Name="PART_VerticalScrollBar" HorizontalAlignment="Right" Maximum="{TemplateBinding ScrollableHeight}" Orientation="Vertical" Style="{StaticResource for_scrollbar}" ViewportSize="{TemplateBinding ViewportHeight}" Value="{TemplateBinding VerticalOffset}" Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}"/> <ScrollBar x:Name="PART_HorizontalScrollBar" Maximum="{TemplateBinding ScrollableWidth}" Orientation="Horizontal" Style="{StaticResource for_scrollbar}" VerticalAlignment="Bottom" Value="{TemplateBinding HorizontalOffset}" ViewportSize="{TemplateBinding ViewportWidth}" Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}"/> </Grid> </Border> <ControlTemplate.Triggers> <EventTrigger RoutedEvent="ScrollChanged" > <BeginStoryboard> <Storyboard> <DoubleAnimation Storyboard.TargetName="PART_VerticalScrollBar" Storyboard.TargetProperty="Opacity" To="0.8" Duration="0:0:1"/> <DoubleAnimation Storyboard.TargetName="PART_VerticalScrollBar" Storyboard.TargetProperty="Opacity" To="0.2" Duration="0:0:1" BeginTime="0:0:1"/> <DoubleAnimation Storyboard.TargetName="PART_HorizontalScrollBar" Storyboard.TargetProperty="Opacity" To="0.8" Duration="0:0:1"/> <DoubleAnimation Storyboard.TargetName="PART_HorizontalScrollBar" Storyboard.TargetProperty="Opacity" To="0.2" Duration="0:0:1" BeginTime="0:0:1"/> </Storyboard> </BeginStoryboard> </EventTrigger> <EventTrigger RoutedEvent="MouseEnter" SourceName="PART_VerticalScrollBar"> <BeginStoryboard> <Storyboard> <DoubleAnimation Storyboard.TargetName="PART_VerticalScrollBar" Storyboard.TargetProperty="Opacity" To="0.8" Duration="0:0:0.7"/> </Storyboard> </BeginStoryboard> </EventTrigger> <EventTrigger RoutedEvent="MouseLeave" SourceName="PART_VerticalScrollBar"> <BeginStoryboard> <Storyboard> <DoubleAnimation Storyboard.TargetName="PART_VerticalScrollBar" Storyboard.TargetProperty="Opacity" To="0.2" Duration="0:0:0.7"/> </Storyboard> </BeginStoryboard> </EventTrigger> <EventTrigger RoutedEvent="MouseEnter" SourceName="PART_HorizontalScrollBar"> <BeginStoryboard> <Storyboard> <DoubleAnimation Storyboard.TargetName="PART_HorizontalScrollBar" Storyboard.TargetProperty="Opacity" To="0.8" Duration="0:0:0.7"/> </Storyboard> </BeginStoryboard> </EventTrigger> <EventTrigger RoutedEvent="MouseLeave" SourceName="PART_HorizontalScrollBar"> <BeginStoryboard> <Storyboard> <DoubleAnimation Storyboard.TargetName="PART_HorizontalScrollBar" Storyboard.TargetProperty="Opacity" To="0.2" Duration="0:0:0.7"/> </Storyboard> </BeginStoryboard> </EventTrigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style> <!--默认ScrollBar--> <Style TargetType="ScrollBar" BasedOn="{StaticResource for_scrollbar}"/> <!--默认ScrollView--> <Style TargetType="ScrollViewer" BasedOn="{StaticResource for_scrollviewer}"/> </ResourceDictionary> App.xaml 引入对应资源字典 点击查看代码 <Application.Resources> <ResourceDictionary> <ResourceDictionary.MergedDictionaries> <!-- ScrollViewer --> <ResourceDictionary Source="pack://application:,,,/WpfMiniaturesDemo;component/ScrollViewerStyle.xaml" /> </ResourceDictionary.MergedDictionaries> </ResourceDictionary> </Application.Resources>