我有一个WPF应用程序,它在垂直堆栈面板中有一系列按钮,类似于DVR菜单的样子。我想出了如何制作一个动画,当每个新的菜单页面被加载时,按钮/控件全部{unfade,fall,deblur,whatever}成为现实,这很好但有点过于统一。我真正喜欢的是根据每个按钮的位置或tabstop属性,在每个按钮上启动动画。因此,例如顶部按钮将是第一个开始,然后是下一个等,直到底部按钮,可能在每次启动之间延迟50毫秒(但是这样第一个按钮不必在第二个按钮之前完成)开始)。当然,我可以为每个按钮制作不同的动画,但我希望有一个更优雅的解决方案。我没有看到将任何控件的属性加载到故事板的BeginTime中的方法。有没有一种很好的方法只使用XAML,或者像这样的东西需要代码隐藏?如果是后者,是否可以将其打包成一个行为,并能够在以后以声明方式加载,或者我是否永远坚持使用命令式代码?
答案 0 :(得分:8)
简短的回答是否定的(据我所知),你不能完全你只想用XAML,这就是原因。
虽然在WPF中有很多方法可以制作动画,但使用XAML制作动画的唯一方法是使用Storyboard。跨元素共享Storyboard的唯一方法是将其打包在诸如Style,ControlTemplate或DataTemplate之类的资源中。但是,为了将Storyboard用作资源,它必须是Freezable,这意味着它不能包含将动画BeginTime与动画目标的属性(例如TabIndex或某些属性)相关联所需的任何数据绑定表达式你的按钮的其他属性)。即使你能以某种方式将动画的BeginTime绑定到Button的属性,你仍然需要使用codebehind来编写ValueConverter来将Button属性值转换为TimeSpan值(你想要的50ms累积延迟)。
因此,为了使完全你想要的东西,你需要使用代码隐藏,如下例所示:
XAML:
<StackPanel HorizontalAlignment="Left" Width="100" Loaded="StackPanel_Loaded">
<Button Content="Button1"/>
<Button Content="Button2"/>
<Button Content="Button3"/>
<Button Content="Button4"/>
<Button Content="Button5"/>
<Button Content="Button6"/>
<Button Content="Button7"/>
<Button Content="Button8"/>
<Button Content="Button9"/>
<Button Content="Button10"/>
</StackPanel>
代码隐藏:
private void StackPanel_Loaded(object sender, RoutedEventArgs e)
{
StackPanel stackPanel = sender as StackPanel;
DoubleAnimation fadeInAnimation = new DoubleAnimation(1.0, new Duration(TimeSpan.FromMilliseconds(200)));
for (int i = 0; i < stackPanel.Children.Count; i++)
{
fadeInAnimation.BeginTime = TimeSpan.FromMilliseconds(i * 50);
stackPanel.Children[i].Opacity = 0.0;
stackPanel.Children[i].BeginAnimation(UIElement.OpacityProperty, (AnimationTimeline)fadeInAnimation.GetAsFrozen());
}
}
话虽如此,有一些方法可以仅使用XAML来估算您想要的行为。例如,您可以使用LinearGradientBrush OpacityMask覆盖StackPanel,并使用单个Storyboard为其设置动画,如下所示:
XAML:
<StackPanel HorizontalAlignment="Left" Width="100">
<StackPanel.OpacityMask>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="Black"/>
<GradientStop x:Name="TransparentGradient" Color="Transparent"/>
</LinearGradientBrush>
</StackPanel.OpacityMask>
<StackPanel.Triggers>
<EventTrigger RoutedEvent="Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="TransparentGradient" Storyboard.TargetProperty="Offset"
To="1.0" Duration="0:0:0.5"/>
<ColorAnimation
Storyboard.TargetName="TransparentGradient" Storyboard.TargetProperty="Color"
To="Black" BeginTime="0:0:0.5" Duration="0:0:0.5"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</StackPanel.Triggers>
<Button Content="Button1"/>
<Button Content="Button2"/>
<Button Content="Button3"/>
<Button Content="Button4"/>
<Button Content="Button5"/>
<Button Content="Button6"/>
<Button Content="Button7"/>
<Button Content="Button8"/>
<Button Content="Button9"/>
<Button Content="Button10"/>
</StackPanel>
这会给你一个很好的从上到下淡入。其他效果也可以通过一点点创造力,但一个建议:尽量避免花费太多时间找到复杂的XAML解决方案,当你可以达到预期的效果只需几行代码。
快乐的编码!