使用VisualBrush时WPF故事板动画问题

时间:2010-01-21 15:21:14

标签: c# wpf animation storyboard

我正在玩故事板,翻动动画和视觉画笔。我遇到了一个问题。下面是一个小样本的xaml和代码隐藏,我很快将它们放在一起试图证明这个问题。

首次启动应用时,会出现红色方块和两个按钮。如果单击“翻转”按钮,红色方块将“翻转”,将出现蓝色方块。实际上,所有发生的事情是,红色正方形所在的StackPanel宽度的比例正在减小,直到它达到零,然后StackPanel,其中一个蓝色正方形,其宽度最初缩放为零,有其宽度增加。如果您单击“翻转”按钮几次,动画看起来很平滑。

现在,如果您点击“反射”按钮,红色/蓝色按钮的反射将添加到各自的StackPanels。现在点击“翻转”按钮仍将导致翻转动画,但它不再是平滑动画。 StackPanels宽度通常不会缩小到零。宽度稍微缩小,然后在完全不可见之前停止。然后另一个StackPanel像往常一样出现。唯一改变的是添加反射,它只是一个VisualBrush。

以下是代码。有没有人知道为什么动画在两种情况下不同(在第二种情况下停滞)?

感谢。

<Window
 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 xml:lang="en-US"
 xmlns:d="http://schemas.microsoft.com/expression/blend/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"
 x:Class="WpfFlipTest.Window1"
 x:Name="Window"
 Title="Window1"
 Width="214" Height="224">
  <Window.Resources>
    <Storyboard x:Key="sbFlip">
      <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="redStack"  Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleX)">
        <SplineDoubleKeyFrame KeyTime="00:00:00.4" Value="0"/>
      </DoubleAnimationUsingKeyFrames>
      <DoubleAnimationUsingKeyFrames BeginTime="00:00:00.4" Storyboard.TargetName="blueStack" Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleX)">
        <SplineDoubleKeyFrame KeyTime="00:00:00.8" Value="1"/>
      </DoubleAnimationUsingKeyFrames>
    </Storyboard>
    <Storyboard x:Key="sbFlipBack">
      <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="blueStack"  Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleX)">
        <SplineDoubleKeyFrame KeyTime="00:00:00.4" Value="0"/>
      </DoubleAnimationUsingKeyFrames>
      <DoubleAnimationUsingKeyFrames BeginTime="00:00:00.4" Storyboard.TargetName="redStack" Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleX)">
        <SplineDoubleKeyFrame KeyTime="00:00:00.8" Value="1"/>
      </DoubleAnimationUsingKeyFrames>
    </Storyboard>
  </Window.Resources>
  <Grid x:Name="LayoutRoot" Background="Gray">
    <Grid.RowDefinitions>
      <RowDefinition Height="Auto"/>
      <RowDefinition Height="Auto"/>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
      <ColumnDefinition Width="Auto"/>
      <ColumnDefinition Width="Auto"/>
    </Grid.ColumnDefinitions>
    <StackPanel Name="redStack" Grid.Row="0" Grid.Column="0" RenderTransformOrigin="0.5,0.5">
      <StackPanel.RenderTransform>
        <ScaleTransform/>
      </StackPanel.RenderTransform>
      <Border Name="redBorder" BorderBrush="Transparent" BorderThickness="4" Width="Auto" Height="Auto">
        <Button Margin="0" Name="redButton" Height="75" Background="Red" Width="105" />
      </Border>
      <Border Width="{Binding ElementName=redBorder, Path=ActualWidth}" 
              Height="{Binding ElementName=redBorder, Path=ActualHeight}" 
              Opacity="0.2" BorderBrush="Transparent" BorderThickness="4" Name="redRefelction" Visibility="Collapsed">
        <Border.OpacityMask>
          <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
            <LinearGradientBrush.GradientStops>
              <GradientStop Offset="0" Color="Black"/>
              <GradientStop Offset=".6" Color="Transparent"/>
            </LinearGradientBrush.GradientStops>
          </LinearGradientBrush>
        </Border.OpacityMask>
        <Border.Background>
          <VisualBrush Visual="{Binding ElementName=redButton}">
            <VisualBrush.Transform>
              <ScaleTransform ScaleX="1" ScaleY="-1" 
                CenterX="52.5" 
                CenterY="37.5" />
            </VisualBrush.Transform>
          </VisualBrush>
        </Border.Background>
      </Border>
    </StackPanel>
    <StackPanel Name="blueStack" Grid.Row="0" Grid.Column="0" RenderTransformOrigin="0.5,0.5">
      <StackPanel.RenderTransform>
        <ScaleTransform ScaleX="0"/>
      </StackPanel.RenderTransform>
      <Border Name="blueBorder" BorderBrush="Transparent" BorderThickness="4" Width="Auto" Height="Auto">
        <Button Grid.Row="0" Grid.Column="1" Margin="0" Width="105" Background="Blue" Name="blueButton" Height="75"/>
      </Border>
      <Border Width="{Binding ElementName=blueBorder, Path=ActualWidth}" 
              Height="{Binding ElementName=blueBorder, Path=ActualHeight}" 
              Opacity="0.2" BorderBrush="Transparent" BorderThickness="4" Name="blueRefelction" Visibility="Collapsed">
        <Border.OpacityMask>
          <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
            <LinearGradientBrush.GradientStops>
              <GradientStop Offset="0" Color="Black"/>
              <GradientStop Offset=".6" Color="Transparent"/>
            </LinearGradientBrush.GradientStops>
          </LinearGradientBrush>
        </Border.OpacityMask>
        <Border.Background>
          <VisualBrush Visual="{Binding ElementName=blueButton}">
            <VisualBrush.Transform>
              <ScaleTransform ScaleX="1" ScaleY="-1" 
                CenterX="52.5" 
                CenterY="37.5" />
            </VisualBrush.Transform>
          </VisualBrush>
        </Border.Background>
      </Border>
    </StackPanel>
    <Button Grid.Row="1" Click="FlipButton_Click" Height="19.45" HorizontalAlignment="Left" VerticalAlignment="Top" Width="76">Flip</Button>
    <Button Grid.Row="0" Grid.Column="1" Click="ReflectionButton_Click" Height="19.45" HorizontalAlignment="Left" VerticalAlignment="Top" Width="76">Reflection</Button>
  </Grid>
</Window>

以下是按钮点击处理程序:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Media.Animation;

namespace WpfFlipTest
{
  public partial class Window1 : Window
  {
    public Window1()
    {
      InitializeComponent();
    }

    bool flipped = false;
    private void FlipButton_Click(object sender, RoutedEventArgs e)
    {
      Storyboard sbFlip = (Storyboard)Resources["sbFlip"];
      Storyboard sbFlipBack = (Storyboard)Resources["sbFlipBack"];

      if (flipped)
      {
        sbFlipBack.Begin();
        flipped = false;
      }
      else
      {
        sbFlip.Begin();
        flipped = true;
      }
    }

    bool reflection = false;
    private void ReflectionButton_Click(object sender, RoutedEventArgs e)
    {
      if (reflection)
      {
        reflection = false;
        redRefelction.Visibility = Visibility.Collapsed;
        blueRefelction.Visibility = Visibility.Collapsed;
      }
      else
      {
        reflection = true;
        redRefelction.Visibility = Visibility.Visible;
        blueRefelction.Visibility = Visibility.Visible;
      }
    }
  }
}







更新:

我一直在测试这个以试图找出导致我看到的问题的原因,我相信我找到了导致问题的原因。

下面我贴了新的xaml和代码隐藏。下面的新样本与原始样本非常相似,只做了一些小修改。 xaml基本上由两个堆栈面板组成,每个面板包含两个边框。每个堆栈面板中的第二个边框是一个可视刷(它上面的边框的反射)。现在,当我单击“翻转”按钮时,一个堆栈面板将其ScaleX缩小为零,而第二个堆栈面板(其初始ScaleX为零)将其ScaleX增加到1.此动画给出了翻转的错觉。还有两个文本块显示每个堆栈面板的比例因子。我添加了这些来尝试诊断我的问题。

问题是(如oringal文章中所述)翻转动画不流畅。每次我按下翻转按钮时,动画都会启动,但只要ScaleX因子达到.14到.16左右,动画看起来就会停止,而堆栈面板永远不会有ScaleX减少到零,所以它们永远不会完全消失。现在,奇怪的是如果我改变下面定义的“frontBorder”和“backBorder”边框的宽度/高度属性来使用explict值而不是Auto,例如Width = 105和Height = 75(以匹配中的按钮)一切正常。动画在我运行它的前两三次口吃,但之后翻转是光滑无瑕的。 (顺便说一句,当第一次运行动画时,背景中是否有某些事情发生,某种初始化,导致它第一次有点慢?)

边框的自动宽度/高度是否可能导致问题?我可以每次都重现它,但我不确定为什么自动宽度/高度会出问题。

以下是样本。谢谢你的帮助。

<Window x:Class="FlipTest.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300">
  <Window.Resources>
    <Storyboard x:Key="sbFlip">
      <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="front"  Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleX)">
        <SplineDoubleKeyFrame KeyTime="00:00:00.5" Value="0"/>
      </DoubleAnimationUsingKeyFrames>
      <DoubleAnimationUsingKeyFrames BeginTime="00:00:00.5" Storyboard.TargetName="back" Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleX)">
        <SplineDoubleKeyFrame KeyTime="00:00:00.5" Value="1"/>
      </DoubleAnimationUsingKeyFrames>
    </Storyboard>
    <Storyboard x:Key="sbFlipBack">
      <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="back"  Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleX)">
        <SplineDoubleKeyFrame KeyTime="00:00:00.5" Value="0"/>
      </DoubleAnimationUsingKeyFrames>
      <DoubleAnimationUsingKeyFrames BeginTime="00:00:00.5" Storyboard.TargetName="front" Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleX)">
        <SplineDoubleKeyFrame KeyTime="00:00:00.5" Value="1"/>
      </DoubleAnimationUsingKeyFrames>
    </Storyboard>
  </Window.Resources>
  <Grid x:Name="LayoutRoot" Background="White" ShowGridLines="True">
    <Grid.RowDefinitions>
      <RowDefinition Height="Auto"/>
      <RowDefinition Height="Auto"/>
      <RowDefinition Height="Auto"/>
      <RowDefinition Height="Auto"/>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
      <ColumnDefinition Width="Auto"/>
      <ColumnDefinition Width="Auto"/>
    </Grid.ColumnDefinitions>
    <StackPanel x:Name="front" RenderTransformOrigin="0.5,0.5">
      <StackPanel.RenderTransform>
        <ScaleTransform/>
      </StackPanel.RenderTransform>
      <Border Name="frontBorder" BorderBrush="Yellow" BorderThickness="2" Width="Auto" Height="Auto">
        <Button Margin="0" Name="redButton" Height="75" Background="Red" Width="105" Click="FlipButton_Click"/>
      </Border>
      <Border Width="{Binding ElementName=frontBorder, Path=ActualWidth}" 
              Height="{Binding ElementName=frontBorder, Path=ActualHeight}" 
              Opacity="0.2" BorderBrush="Transparent">
        <Border.OpacityMask>
          <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
            <LinearGradientBrush.GradientStops>
              <GradientStop Offset="0" Color="Black"/>
              <GradientStop Offset=".6" Color="Transparent"/>
            </LinearGradientBrush.GradientStops>
          </LinearGradientBrush>
        </Border.OpacityMask>
        <Border.Background>
          <VisualBrush Visual="{Binding ElementName=frontBorder}">
            <VisualBrush.Transform>
              <ScaleTransform ScaleX="1" ScaleY="-1" 
                CenterX="52.5" 
                CenterY="37.5" />
            </VisualBrush.Transform>
          </VisualBrush>
        </Border.Background>
      </Border>
    </StackPanel>
    <StackPanel x:Name="back" RenderTransformOrigin="0.5,0.5">
      <StackPanel.RenderTransform>
        <ScaleTransform ScaleX="0"/>
      </StackPanel.RenderTransform>
      <Border Name="backBorder" BorderBrush="Yellow" BorderThickness="2" Width="Auto" Height="Auto">
        <Button Margin="0" Width="105" Background="Blue" Name="blueButton" Height="75" Click="FlipButton_Click"/>
      </Border>
      <Border Width="{Binding ElementName=backBorder, Path=ActualWidth}" 
              Height="{Binding ElementName=backBorder, Path=ActualHeight}" 
              Opacity="0.2" BorderBrush="Transparent">
        <Border.OpacityMask>
          <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
            <LinearGradientBrush.GradientStops>
              <GradientStop Offset="0" Color="Black"/>
              <GradientStop Offset=".6" Color="Transparent"/>
            </LinearGradientBrush.GradientStops>
          </LinearGradientBrush>
        </Border.OpacityMask>
        <Border.Background>
          <VisualBrush Visual="{Binding ElementName=backBorder}">
            <VisualBrush.Transform>
              <ScaleTransform ScaleX="1" ScaleY="-1" 
                CenterX="52.5" 
                CenterY="37.5" />
            </VisualBrush.Transform>
          </VisualBrush>
        </Border.Background>
      </Border>
    </StackPanel>
    <Button Grid.Row="1" Click="FlipButton_Click" Height="19.45" HorizontalAlignment="Left" VerticalAlignment="Top" Width="76">Flip</Button>
    <TextBlock Grid.Row="2" Grid.Column="0" Foreground="DarkRed" Height="19.45" HorizontalAlignment="Left" VerticalAlignment="Top" Width="76" Text="{Binding ElementName=front, Path=(UIElement.RenderTransform).(ScaleTransform.ScaleX)}"/>
    <TextBlock Grid.Row="3" Grid.Column="0" Foreground="DarkBlue" Height="19.45" HorizontalAlignment="Left" VerticalAlignment="Top" Width="76" Text="{Binding ElementName=back, Path=(UIElement.RenderTransform).(ScaleTransform.ScaleX)}"/>
  </Grid>
</Window>

代码隐藏:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Media.Animation;

namespace FlipTest
{
  /// <summary>
  /// Interaction logic for Window1.xaml
  /// </summary>
  public partial class Window1 : Window
  {
    public Window1()
    {
      InitializeComponent();
    }

    bool flipped = false;
    private void FlipButton_Click(object sender, RoutedEventArgs e)
    {
      Storyboard sbFlip = (Storyboard)Resources["sbFlip"];
      Storyboard sbFlipBack = (Storyboard)Resources["sbFlipBack"];

      if (flipped)
      {
        sbFlipBack.Begin();
        flipped = false;
      }
      else
      {
        sbFlip.Begin();
        flipped = true;
      }
    }
  }
}

1 个答案:

答案 0 :(得分:0)

我在新的x64机器上再试一次,动画运行顺利,没有任何问题。我之前看到的一定与我的旧机器性能不佳有关。