WPF如何正确动画颜色变化
WPF how to properly animate color changing
虽然一次性更改背景很容易,而且它已经有很多 answers,但我如何才能始终如一地为颜色设置动画 changing(例如,不是一次,不是为单色)。
举一个问题的玩具例子,假设我有一个 Rectangle
和三个 RadioButton
分别命名为 "Red"、"Blue" 和 "Green",我如何制作动画矩形的填充颜色,以便它对应于选中的单选按钮(例如,每当您单击 "Blue" 并且矩形变为蓝色)?
<StackPanel HorizontalAlignment="Left">
<Rectangle Width="50" Height="50" Style="{StaticResource ColorChangingStyle}"/>
<RadioButton Name="Red" Content="Red" GroupName="Group1" IsChecked="True"/>
<RadioButton Name="Green" Content="Green" GroupName="Group1"/>
<RadioButton Name="Blue" Content="Blue" GroupName="Group1"/>
</StackPanel>
我现在面临的问题是,只要有多个动画附加到 Rectangle
的填充颜色,由于动画优先级,它会以各种方式失败,例如,如果有"Red"、"Green" 和 "Blue" 的多个触发器:
<DataTrigger Binding="{Binding IsChecked, ElementName=Blue}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard Name="ToBlue">
<Storyboard>
<ColorAnimation Storyboard.TargetProperty="(Rectangle.Fill).(SolidColorBrush.Color)" To="Blue" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
当填充为蓝色时单击 "Green",它将保持蓝色(因为 "ToBlue" 定义在 "ToGreen" 下方)。更糟糕的是,如果您尝试事先删除 "ToBlue":
<RemoveStoryboard BeginStoryboardName="ToBlue"/>
它将从默认颜色变为绿色而不是从蓝色变为绿色。
是的,问题是......这是一个 "BUG"。触发器是 "styling" 元素的旧方法。新方法使用 VisualStates
一个例子是:
注意:此示例不适合您。
<VisualStateManager.VisualStateGroups>
<VisualStateGroup Name="ColorStates">
<VisualState Name="ToGreen">
<Storyboard>
<ColorAnimation To="Green"
Storyboard.TargetProperty="Fill"/>
</Storyboard>
</VisualState>
<VisualState Name="ToBlue">
<Storyboard>
<ColorAnimation To="Blue"
Storyboard.TargetProperty="Fill"/>
</Storyboard>
</VisualState>
<VisualState Name="ToRed">
<Storyboard>
<ColorAnimation To="Red"
Storyboard.TargetProperty="Fill"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
然后为了改变状态你可以使用一点 c#
VisualStateManager.GoToState(YOUR_CONTROL, "YOUR_STATE", true);
或者太难看的话可以做一个状态行为
public class StateBehavior
{
public static readonly DependencyProperty StateProperty =
DependencyProperty.RegisterAttached("State",
typeof(string),
typeof(StateBehavior),
new UIPropertyMetadata(null, StateChanged));
internal static void StateChanged(DependencyObject target, DependencyPropertyChangedEventArgs args)
{
if (args.NewValue != null)
VisualStateManager.GoToState((FrameworkElement)target, args.NewValue, true);
}
}
并像这样使用它
<YOUR_CONTROL local:StateBehavior.State="{Binding Path=YOUR_STATE_DATA, Mode=TwoWay}" />
奖金
你可以使用 Transitions 来获得一些效果(我知道这是题外话)
PS:很抱歉没有显示如何解决您的问题。 (我只是懒得切换到 Windows,我目前在 Linux)
虽然一次性更改背景很容易,而且它已经有很多 answers,但我如何才能始终如一地为颜色设置动画 changing(例如,不是一次,不是为单色)。
举一个问题的玩具例子,假设我有一个 Rectangle
和三个 RadioButton
分别命名为 "Red"、"Blue" 和 "Green",我如何制作动画矩形的填充颜色,以便它对应于选中的单选按钮(例如,每当您单击 "Blue" 并且矩形变为蓝色)?
<StackPanel HorizontalAlignment="Left">
<Rectangle Width="50" Height="50" Style="{StaticResource ColorChangingStyle}"/>
<RadioButton Name="Red" Content="Red" GroupName="Group1" IsChecked="True"/>
<RadioButton Name="Green" Content="Green" GroupName="Group1"/>
<RadioButton Name="Blue" Content="Blue" GroupName="Group1"/>
</StackPanel>
我现在面临的问题是,只要有多个动画附加到 Rectangle
的填充颜色,由于动画优先级,它会以各种方式失败,例如,如果有"Red"、"Green" 和 "Blue" 的多个触发器:
<DataTrigger Binding="{Binding IsChecked, ElementName=Blue}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard Name="ToBlue">
<Storyboard>
<ColorAnimation Storyboard.TargetProperty="(Rectangle.Fill).(SolidColorBrush.Color)" To="Blue" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
当填充为蓝色时单击 "Green",它将保持蓝色(因为 "ToBlue" 定义在 "ToGreen" 下方)。更糟糕的是,如果您尝试事先删除 "ToBlue":
<RemoveStoryboard BeginStoryboardName="ToBlue"/>
它将从默认颜色变为绿色而不是从蓝色变为绿色。
是的,问题是......这是一个 "BUG"。触发器是 "styling" 元素的旧方法。新方法使用 VisualStates
一个例子是:
注意:此示例不适合您。
<VisualStateManager.VisualStateGroups>
<VisualStateGroup Name="ColorStates">
<VisualState Name="ToGreen">
<Storyboard>
<ColorAnimation To="Green"
Storyboard.TargetProperty="Fill"/>
</Storyboard>
</VisualState>
<VisualState Name="ToBlue">
<Storyboard>
<ColorAnimation To="Blue"
Storyboard.TargetProperty="Fill"/>
</Storyboard>
</VisualState>
<VisualState Name="ToRed">
<Storyboard>
<ColorAnimation To="Red"
Storyboard.TargetProperty="Fill"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
然后为了改变状态你可以使用一点 c#
VisualStateManager.GoToState(YOUR_CONTROL, "YOUR_STATE", true);
或者太难看的话可以做一个状态行为
public class StateBehavior
{
public static readonly DependencyProperty StateProperty =
DependencyProperty.RegisterAttached("State",
typeof(string),
typeof(StateBehavior),
new UIPropertyMetadata(null, StateChanged));
internal static void StateChanged(DependencyObject target, DependencyPropertyChangedEventArgs args)
{
if (args.NewValue != null)
VisualStateManager.GoToState((FrameworkElement)target, args.NewValue, true);
}
}
并像这样使用它
<YOUR_CONTROL local:StateBehavior.State="{Binding Path=YOUR_STATE_DATA, Mode=TwoWay}" />
奖金
你可以使用 Transitions 来获得一些效果(我知道这是题外话)
PS:很抱歉没有显示如何解决您的问题。 (我只是懒得切换到 Windows,我目前在 Linux)