如何自定义WPF不确定状态进度条的动画速度与指示条宽度
实现方案
你之前的写法无法生效,核心原因是Animation元素是ProgressBar默认控件模板的内部元素,在外层Grid定义VisualStateManager根本访问不到模板内部的目标,自然覆盖不了默认动画。
要实现调慢不确定态动画速度、加宽内部指示条的需求,直接重写ProgressBar的控件模板即可,不需要额外写后台逻辑调用VSM。
核心调整点
- 动画速度:修改Indeterminate状态下Storyboard的总时长,时长越长动画播放速度越慢
- 指示条宽度:直接修改模板内滑动指示条元素的最小宽度,数值越大指示条越宽
完整可用代码
把下面的自定义样式放在窗口资源中,给ProgressBar引用该样式即可:
<Window x:Class="IndeterminateProgressBarTest.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="100" Width="700"> <Window.Resources> <Style x:Key="SlowWideProgressBarStyle" TargetType="ProgressBar"> <Setter Property="Foreground" Value="#0078D4"/> <Setter Property="Background" Value="#F0F0F0"/> <Setter Property="BorderThickness" Value="0"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="ProgressBar"> <Grid> <VisualStateManager.VisualStateGroups> <VisualStateGroup x:Name="CommonStates"> <VisualState x:Name="Determinate"> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="IndeterminateIndicator" Storyboard.TargetProperty="Visibility"> <DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed"/> </ObjectAnimationUsingKeyFrames> <DoubleAnimation Storyboard.TargetName="DeterminateIndicator" Storyboard.TargetProperty="Width" To="{TemplateBinding Value}" Duration="0:0:0.2"/> </Storyboard> </VisualState> <VisualState x:Name="Indeterminate"> <Storyboard RepeatBehavior="Forever"> <!-- 总时长设为4秒,比默认2秒慢一倍,需要更慢就把KeyTime改大 --> <DoubleAnimationUsingKeyFrames Storyboard.TargetName="IndeterminateIndicator" Storyboard.TargetProperty="(UIElement.RenderTransform).(TranslateTransform.X)"> <EasingDoubleKeyFrame KeyTime="0" Value="-350"/> <EasingDoubleKeyFrame KeyTime="0:0:4" Value="650"/> </DoubleAnimationUsingKeyFrames> </Storyboard> </VisualState> </VisualStateGroup> </VisualStateManager.VisualStateGroups> <!-- 进度条轨道 --> <Border Background="{TemplateBinding Background}" CornerRadius="4"/> <!-- 确定状态进度指示 --> <Border x:Name="DeterminateIndicator" HorizontalAlignment="Left" Background="{TemplateBinding Foreground}" CornerRadius="4"/> <!-- 不确定状态滑动指示条 MinWidth设为350,比默认180宽近一倍,需要更宽就改这个值 --> <Border x:Name="IndeterminateIndicator" HorizontalAlignment="Left" Background="{TemplateBinding Foreground}" CornerRadius="4" MinWidth="350" Height="{TemplateBinding Height}"> <Border.RenderTransform> <TranslateTransform X="-350"/> </Border.RenderTransform> </Border> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style> </Window.Resources> <Grid> <ProgressBar Width="600" Height="25" IsIndeterminate="True" Style="{StaticResource SlowWideProgressBarStyle}"/> </Grid> </Window>
参数自定义说明
- 调整动画速度:修改
Indeterminate状态下第二个EasingDoubleKeyFrame的KeyTime值,比如改成0:0:6动画速度会更慢 - 调整指示条宽度:修改
IndeterminateIndicator的MinWidth值,数值越大滑动的指示条越宽,注意同步修改动画起始X值和初始TranslateTransform的X值,保证动画首尾衔接自然 - 不需要保留确定状态功能的话,可以直接删掉模板里的
DeterminateIndicator相关代码,进一步简化模板
内容的提问来源于stack exchange,提问作者Wellwoah
相关产品推荐
相关产品推荐

