【问题标题】:WPF how to properly animate color changingWPF如何正确动画颜色变化
【发布时间】:2019-12-22 14:44:49
【问题描述】:

虽然一次性背景更改很容易并且已经有很多answers,但我如何才能始终如一地为颜色设置动画更改(例如,不是一次,不是单一颜色)。
举一个问题的玩具示例,假设我有一个 Rectangle 和三个名为“红色”、“蓝色”和“绿色”的 RadioButtons,如何为矩形的填充颜色设置动画,使其对应于选中单选按钮(例如,当您单击“蓝色”并且矩形变为蓝色时)?

<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 的填充颜色附加多个动画时,由于动画优先级,它会以各种方式惨遭失败,例如,如果有多个触发器“红色”、“绿色”和“蓝色”:

<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>

当填充为蓝色时单击“绿色”,它将保持蓝色(因为“ToBlue”定义在“ToGreen”下方)。更糟糕的是,如果您尝试事先删除“ToBlue”:

<RemoveStoryboard BeginStoryboardName="ToBlue"/>

它会从默认颜色变为绿色,而不是从蓝色变为绿色。

【问题讨论】:

  • 加分项:即使在动画进行时目标颜色发生变化,它也会持续工作。
  • @Frenchy 您建议的具有 RadioButtons 的“推送”语义的解决方案对我来说是有效的(不是我投票)。虽然毫无疑问VisualStateManager 更优雅,因为它允许更轻松的绑定。

标签: c# wpf xaml animation wpf-animation


【解决方案1】:

是的,问题是......这是一个“BUG”。触发器是“样式化”元素的旧方法。新方法是使用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);

或者如果太丑,你可以做一个State Behavior

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上)

【讨论】:

  • 很好,完美无瑕,但最重要的是始终如一。此外,即使是“基本”示例也满足了奖励点 - 动画非常流畅。只是给实现者的说明:您很可能需要为 Rectangle 定义新实例 &lt;SolidColorBrush/&gt; 否则应用程序会因一些神秘的异常而崩溃。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-12-15
  • 2014-01-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-15
  • 2011-04-26
相关资源
最近更新 更多