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)