当左边距变为负值时,动画减慢

时间:2013-06-10 11:35:09

标签: wpf animation margin

我试图让一个多边形完全从屏幕左侧移动,穿过屏幕,然后完全离开屏幕右侧,然后再移回。

我已经开始工作了。但是,出于某种原因,只要左边距变为负值,动画就会突然减慢。一旦左边距变为正,它就会再次加速。

为什么会这样?我怎么能阻止它?

以下是演示此内容的完整代码:

<Window x:Class="Geometry.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <PathGeometry x:Key="MyGeometry">
            <PathGeometry.Figures>
                <PathFigure>
                    <PathFigure.Segments>
                        <LineSegment Point="0.30,0" />
                        <LineSegment Point="0.70,1" />
                        <LineSegment Point="0.40,1" />
                        <LineSegment Point="0,0" />
                    </PathFigure.Segments>
                </PathFigure>
            </PathGeometry.Figures>
        </PathGeometry>
        <Storyboard x:Key="MovingAnimation">
            <ThicknessAnimationUsingKeyFrames RepeatBehavior="1:0:0" FillBehavior="HoldEnd" Storyboard.TargetName="_path" Storyboard.TargetProperty="Margin" >
                <DiscreteThicknessKeyFrame KeyTime="0:0:0" Value="-2.0,0,0,0"  />
                <LinearThicknessKeyFrame KeyTime="0:0:10" Value="1.0,0,0,0"  />
                <LinearThicknessKeyFrame KeyTime="0:0:20" Value="-2.0,0,0,0"  />
            </ThicknessAnimationUsingKeyFrames>
        </Storyboard>
    </Window.Resources>
    <Window.Triggers>
        <EventTrigger RoutedEvent="Window.Loaded">
            <BeginStoryboard Storyboard="{StaticResource MovingAnimation}" ></BeginStoryboard>
        </EventTrigger>
    </Window.Triggers>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <StackPanel Grid.Row="0" Orientation="Horizontal">
            <Label>Margin:</Label>
            <TextBlock Text="{Binding ElementName=_path, Path=Margin.Left, StringFormat={}{0:0.#}}" />
        </StackPanel>
    <Canvas Name="_canvas" Grid.Row="1">
        <Border Margin="0" Width="1" Height="1" VerticalAlignment="Center" HorizontalAlignment="Center">
            <Border.RenderTransform>
                <ScaleTransform 
                    ScaleX="{Binding ElementName=_canvas, Path=ActualWidth}" 
                    ScaleY="{Binding ElementName=_canvas, Path=ActualHeight}"
                    CenterX="0"
                    CenterY="0">
                </ScaleTransform>
            </Border.RenderTransform>
            <Path 
                Name="_path" 
                Fill="#CCCCFF" 
                Data="{StaticResource MyGeometry}" 
                Width="1.0" 
                Height="1.0" 
                >
        </Path>
        </Border>
    </Canvas>
    </Grid>
</Window>

3 个答案:

答案 0 :(得分:4)

我没有解释为什么负边距动画缓慢,但我找到了解决方法。

我没有为Margin的{​​{1}}设置动画,而是在Path包含路径的X对象上设置TranslateTransform的{​​{1}}值。 我必须将Border放在TranslateTransform前面,以便在比例之前应用翻译。这使您可以在动画中使用与ScaleTransform

相同的值
Margin

丑陋的部分是我无法找到一种快速方法将关键帧中的值直接应用于 <Storyboard x:Key="MovingAnimation"> <ThicknessAnimationUsingKeyFrames RepeatBehavior="1:0:0" Storyboard.TargetName="_blank" Storyboard.TargetProperty="Margin" > <LinearThicknessKeyFrame KeyTime="0:0:0" Value="-1.5,0,0,0" /> <LinearThicknessKeyFrame KeyTime="0:0:10" Value="1,0,0,0" /> <LinearThicknessKeyFrame KeyTime="0:0:20" Value="-1.5,0,0,0" /> </ThicknessAnimationUsingKeyFrames> </Storyboard> 的{​​{1}}属性,因此我欺骗并使用了元素绑定和占位符X对象。

TranslateTransform

即使动画仍然被应用于Canvas然后再通过元素绑定应用于 <StackPanel Grid.Row="0" Orientation="Horizontal" Margin="5"> <TextBlock Margin="0,0,5,0" Text="Margin.Left:"/> <TextBlock Text="{Binding ElementName=_blank, Path=Margin.Left, StringFormat={}{0:0.#}}" /> </StackPanel> <Canvas Name="_blank" /> <!--Placeholder object--> <Canvas Name="_canvas" Grid.Row="1"> <Border Margin="0" Width="1" Height="1" Name="_border" VerticalAlignment="Center" HorizontalAlignment="Center"> <Border.RenderTransform> <TransformGroup> <TranslateTransform X="{Binding Margin.Left, ElementName=_blank}"/> <ScaleTransform ScaleX="{Binding ElementName=_canvas, Path=ActualWidth}" ScaleY="{Binding ElementName=_canvas, Path=ActualHeight}" CenterX="0" CenterY="0"> </ScaleTransform> </TransformGroup> </Border.RenderTransform> ,负边距的延迟也就消失了。

我怀疑负边距延迟与Margin中正在缩放的​​TranslateTransform有关,但这是我的推测。

如果您可以找到将Path值直接绑定到Border的{​​{1}}属性的方法,那么这将使这种解决方法更加难看。

修改 弄清楚要使用的正确绑定:

KeyFrame

这消除了额外的画布占位符对象。

X

答案 1 :(得分:3)

动画保证金属性将触发额外的度量/排列传递,这反过来会对性能产生更大的影响(尽管在此示例中可能不会引人注意)。另一方面,“仅渲染”属性的动画不会触发布局重新排列,因此性能更友好。

请考虑一下,我想,你想做一些更简单的方法来做你想做的事情:

<Window x:Class="Geometry.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="518" Width="530">
<Window.Resources>
    <PathGeometry x:Key="MyGeometry">
        <PathGeometry.Figures>
            <PathFigure>
                <PathFigure.Segments>
                    <LineSegment Point="0.30,0" />
                    <LineSegment Point="0.70,1" />
                    <LineSegment Point="0.40,1" />
                    <LineSegment Point="0,0" />
                </PathFigure.Segments>
            </PathFigure>
        </PathGeometry.Figures>
    </PathGeometry>
    <Storyboard x:Key="MovingAnimation">
        <DoubleAnimationUsingKeyFrames RepeatBehavior="1:0:0" FillBehavior="HoldEnd" Storyboard.TargetName="_scaleTransform" Storyboard.TargetProperty="CenterX" >
            <LinearDoubleKeyFrame KeyTime="0:0:0" Value="1.2" />
            <LinearDoubleKeyFrame KeyTime="0:0:10" Value="-0.5" />
            <LinearDoubleKeyFrame KeyTime="0:0:20" Value="1.2" />
        </DoubleAnimationUsingKeyFrames>
    </Storyboard>
</Window.Resources>
<Window.Triggers>
    <EventTrigger RoutedEvent="Window.Loaded">
        <BeginStoryboard Storyboard="{StaticResource MovingAnimation}" ></BeginStoryboard>
    </EventTrigger>
</Window.Triggers>
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
        <RowDefinition Height="*" />
    </Grid.RowDefinitions>
    <StackPanel Grid.Row="0" Orientation="Horizontal">
        <Label>Margin:</Label>
        <TextBlock Text="{Binding ElementName=_scaleTransform, Path=CenterX, StringFormat={}{0:0.#}}" VerticalAlignment="Center" />
    </StackPanel>
<!--
    <Border Grid.Row="1" Margin="150" BorderBrush="Red" BorderThickness="1">
-->
    <Grid Name="_canvas" Grid.Row="1">
        <Path Name="_path" Fill="#CCCCFF" Data="{StaticResource MyGeometry}" 
              Width="1.0"
              Height="1.0"
              HorizontalAlignment="Center"
              VerticalAlignment="Center">
            <Path.RenderTransform>
                <ScaleTransform x:Name="_scaleTransform"
                    ScaleX="{Binding ElementName=_canvas, Path=ActualWidth}" 
                    ScaleY="{Binding ElementName=_canvas, Path=ActualHeight}"
                    CenterX="1.2"
                    CenterY="0.5">
                </ScaleTransform>
            </Path.RenderTransform>
        </Path>
    </Grid>
<!--
    </Border>
-->
</Grid>
</Window>

答案 2 :(得分:1)

从目前为止的两个答案中可以清楚地看到,如果你想在屏幕上形成一个形状,请不要为边距设置动画。

  • Stewbob通过设置转换变换的X值来解决问题。
  • sevenate通过设置比例变换的中心X值来解决问题。

另一个解决方案是,不是将多边形包裹在边框中并为边距设置动画,而是将其包裹在画布中并为左值设置动画。

将它包装在画布中:

    <Canvas Name="_canvasFrame" Grid.Row="1">
        <Canvas Margin="0" Width="1" Height="1">
            <Canvas.RenderTransform>
                <ScaleTransform 
                ScaleX="{Binding ElementName=_canvasFrame, Path=ActualWidth}" 
                ScaleY="{Binding ElementName=_canvasFrame, Path=ActualHeight}"
                CenterX="0"
                CenterY="0">
                </ScaleTransform>
            </Canvas.RenderTransform>
            <Path 
            Name="_path" 
            Fill="#CCCCFF" 
            Data="{StaticResource MyGeometry}" 
            Width="1.0" Height="1.0" 
            >
            </Path>
        </Canvas>
    </Canvas>

然后设置左值的动画:

    <Storyboard x:Key="MovingAnimation">
        <DoubleAnimationUsingKeyFrames 
                          RepeatBehavior="1:0:0" 
                          FillBehavior="HoldEnd" 
                          Storyboard.TargetName="_path" 
                          Storyboard.TargetProperty="(Canvas.Left)" >
            <DiscreteDoubleKeyFrame KeyTime="0:0:0" Value="-1.0"  />
            <LinearDoubleKeyFrame KeyTime="0:0:10" Value="1.0"  />
            <LinearDoubleKeyFrame KeyTime="0:0:20" Value="-1.0"  />
        </DoubleAnimationUsingKeyFrames>
    </Storyboard>