WPF中ColorAnimation无法使用LinearGradientBrush的替代方案求助
问题描述
想要在ToggleButton处于选中状态时,将其内部名为Pill的Border控件背景设置为渐变效果。但WPF的ColorAnimation不支持直接使用LinearGradientBrush,运行代码时抛出错误:ArgumentException: 'System.Windows.Media.LinearGradientBrush' is not a valid value for property 'To',寻求实现该效果的替代方案。
用户尝试的代码示例:
<ControlTemplate TargetType="{x:Type ToggleButton}"> <Border Background="DarkGray" Style="{StaticResource ToggleBrushOn}" x:Name="Pill"> <Border x:Name="Circle" Background="#FFFFFF" Width="22" Height="22" CornerRadius="22" Margin="35,5,5,5" HorizontalAlignment="Right"/> <Border.Clip> <RectangleGeometry Rect="0,0,65,32" RadiusX="15" RadiusY="32"/> </Border.Clip> </Border> <ControlTemplate.Triggers> <Trigger Property="IsChecked" Value="True"> <Trigger.EnterActions> <BeginStoryboard> <Storyboard> <ColorAnimation Duration="0:0:0.1" Storyboard.TargetName="Pill" Storyboard.TargetProperty="(Control.Background)" To="{StaticResource tbGradient}"/> </Storyboard> </BeginStoryboard> </Trigger.EnterActions> <Trigger.ExitActions> <BeginStoryboard> <Storyboard> <ColorAnimation Duration="0:0:0.1" Storyboard.TargetName="Pill" Storyboard.TargetProperty="(Control.Background)" To="DarkGray"/> </Storyboard> </BeginStoryboard> </Trigger.ExitActions> </Trigger> </ControlTemplate.Triggers> </ControlTemplate>
替代方案
方法1:用ObjectAnimationUsingKeyFrames直接切换Brush
ColorAnimation只能给Color类型属性做动画,而Background是Brush类型,换用ObjectAnimationUsingKeyFrames就能直接切换不同Brush,包括渐变Brush:
<ControlTemplate TargetType="{x:Type ToggleButton}"> <Border Background="DarkGray" x:Name="Pill"> <Border x:Name="Circle" Background="#FFFFFF" Width="22" Height="22" CornerRadius="22" Margin="35,5,5,5" HorizontalAlignment="Right"/> <Border.Clip> <RectangleGeometry Rect="0,0,65,32" RadiusX="15" RadiusY="32"/> </Border.Clip> </Border> <ControlTemplate.Resources> <!-- 定义渐变Brush资源 --> <LinearGradientBrush x:Key="tbGradient" StartPoint="0,0" EndPoint="1,0"> <GradientStop Color="#FF61D0FF" Offset="0"/> <GradientStop Color="#FF0094FF" Offset="1"/> </LinearGradientBrush> </ControlTemplate.Resources> <ControlTemplate.Triggers> <Trigger Property="IsChecked" Value="True"> <Trigger.EnterActions> <BeginStoryboard> <Storyboard> <ObjectAnimationUsingKeyFrames Duration="0:0:0.1" Storyboard.TargetName="Pill" Storyboard.TargetProperty="Background"> <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource tbGradient}"/> </ObjectAnimationUsingKeyFrames> </Storyboard> </BeginStoryboard> </Trigger.EnterActions> <Trigger.ExitActions> <BeginStoryboard> <Storyboard> <ObjectAnimationUsingKeyFrames Duration="0:0:0.1" Storyboard.TargetName="Pill" Storyboard.TargetProperty="Background"> <DiscreteObjectKeyFrame KeyTime="0" Value="DarkGray"/> </ObjectAnimationUsingKeyFrames> </Storyboard> </BeginStoryboard> </Trigger.ExitActions> </Trigger> </ControlTemplate.Triggers> </ControlTemplate>
注意:DiscreteObjectKeyFrame是直接切换值,没有平滑过渡效果。如果需要渐变Brush的平滑过渡,用下面的方法。
方法2:用VisualStateManager管理状态切换
WPF的VisualStateManager专门用于控件状态管理,用它实现状态切换更规范:
<ControlTemplate TargetType="{x:Type ToggleButton}"> <Grid> <VisualStateManager.VisualStateGroups> <VisualStateGroup x:Name="CheckStates"> <VisualState x:Name="Unchecked"> <Storyboard> <ObjectAnimationUsingKeyFrames Duration="0:0:0.1" Storyboard.TargetName="Pill" Storyboard.TargetProperty="Background"> <DiscreteObjectKeyFrame KeyTime="0" Value="DarkGray"/> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState> <VisualState x:Name="Checked"> <Storyboard> <ObjectAnimationUsingKeyFrames Duration="0:0:0.1" Storyboard.TargetName="Pill" Storyboard.TargetProperty="Background"> <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource tbGradient}"/> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState> </VisualStateGroup> </VisualStateManager.VisualStateGroups> <Border Background="DarkGray" x:Name="Pill"> <Border x:Name="Circle" Background="#FFFFFF" Width="22" Height="22" CornerRadius="22" Margin="35,5,5,5" HorizontalAlignment="Right"/> <Border.Clip> <RectangleGeometry Rect="0,0,65,32" RadiusX="15" RadiusY="32"/> </Border.Clip> </Border> </Grid> <ControlTemplate.Resources> <LinearGradientBrush x:Key="tbGradient" StartPoint="0,0" EndPoint="1,0"> <GradientStop Color="#FF61D0FF" Offset="0"/> <GradientStop Color="#FF0094FF" Offset="1"/> </LinearGradientBrush> </ControlTemplate.Resources> </ControlTemplate>
方法3:给渐变Brush的颜色做动画(实现平滑过渡)
如果想要从纯色到渐变有平滑过渡效果,可以直接给渐变Brush里的GradientStop的Color属性做动画:
<ControlTemplate TargetType="{x:Type ToggleButton}"> <Border x:Name="Pill"> <Border.Background> <LinearGradientBrush x:Name="PillGradient" StartPoint="0,0" EndPoint="1,0"> <GradientStop x:Name="GradientStop1" Color="DarkGray" Offset="0"/> <GradientStop x:Name="GradientStop2" Color="DarkGray" Offset="1"/> </LinearGradientBrush> </Border.Background> <Border x:Name="Circle" Background="#FFFFFF" Width="22" Height="22" CornerRadius="22" Margin="35,5,5,5" HorizontalAlignment="Right"/> <Border.Clip> <RectangleGeometry Rect="0,0,65,32" RadiusX="15" RadiusY="32"/> </Border.Clip> </Border> <ControlTemplate.Triggers> <Trigger Property="IsChecked" Value="True"> <Trigger.EnterActions> <BeginStoryboard> <Storyboard> <ColorAnimation Duration="0:0:0.1" Storyboard.TargetName="GradientStop1" Storyboard.TargetProperty="Color" To="#FF61D0FF"/> <ColorAnimation Duration="0:0:0.1" Storyboard.TargetName="GradientStop2" Storyboard.TargetProperty="Color" To="#FF0094FF"/> </Storyboard> </BeginStoryboard> </Trigger.EnterActions> <Trigger.ExitActions> <BeginStoryboard> <Storyboard> <ColorAnimation Duration="0:0:0.1" Storyboard.TargetName="GradientStop1" Storyboard.TargetProperty="Color" To="DarkGray"/> <ColorAnimation Duration="0:0:0.1" Storyboard.TargetName="GradientStop2" Storyboard.TargetProperty="Color" To="DarkGray"/> </Storyboard> </BeginStoryboard> </Trigger.ExitActions> </Trigger> </ControlTemplate.Triggers> </ControlTemplate>
这种方法会让颜色从纯色平滑过渡到渐变效果,体验更流畅。
内容的提问来源于stack exchange,提问作者megahendrik
相关产品推荐
相关产品推荐

