我一直试图弄清楚如何在viewmodel中的属性更新时有效地触发视图中的动画,其中动画取决于所述属性的值.
我在一个简单的应用程序中使用单个View和viewmodel重新创建了我的问题.这里的目标是使用ColorAnimation转换矩形的颜色变化.作为参考,我一直在使用Josh Smith的MVVM Foundation软件包.
示例项目可以是downloaded here.
总而言之,我想在Color属性更改时为View中的颜色过渡设置动画.
MainWindow.xaml
<Window x:Class="MVVM.ColorAnimation.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:ColorAnimation="clr-namespace:MVVM.ColorAnimation" Title="MainWindow" Height="350" Width="525"> <Window.DataContext> <ColorAnimation:MainWindowviewmodel /> </Window.DataContext> <Grid> <Grid.RowDefinitions> <RowDefinition Height="*" /> <RowDefinition Height="40" /> </Grid.RowDefinitions> <Rectangle Margin="10"> <Rectangle.Fill> <SolidColorBrush Color="{Binding Color}"/> </Rectangle.Fill> </Rectangle> <StackPanel Orientation="Horizontal" Grid.Row="1"> <Button Command="{Binding BlueCommand}" Width="100">Blue</Button> <Button Command="{Binding GreenCommand}" Width="100">Green</Button> </StackPanel> </Grid> </Window>
MainWindowviewmodel.cs
namespace MVVM.ColorAnimation { using System.Windows.Input; using System.Windows.Media; using MVVM; public class MainWindowviewmodel : ObservableObject { private ICommand blueCommand; private ICommand greenCommand; public ICommand BlueCommand { get { return this.blueCommand ?? (this.blueCommand = new RelayCommand(this.TurnBlue)); } } private void TurnBlue() { this.Color = Colors.Blue; } public ICommand GreenCommand { get { return this.greenCommand ?? (this.greenCommand = new RelayCommand(this.TurnGreen)); } } private void TurnGreen() { this.Color = Colors.Green; } private Color color = Colors.Red; public Color Color { get { return this.color; } set { this.color = value; RaisePropertyChanged("Color"); } } } }
无论如何从View中触发ColorAnimation而不是值之间的即时转换?我目前这样做的方式是另一个应用程序非常混乱,因为我通过viewmodel属性设置viewmodel,然后使用PropertyObserver监视值更改,然后创建动画并从代码隐藏中触发它:
this.colorObserver = new PropertyObserver<Player>(value) .RegisterHandler(n => n.Color,this.CreateColorAnimation);
在我处理许多颜色和许多潜在动画的情况下,这变得非常混乱,并且弄乱了我手动将viewmodel传递给View而不是简单地通过ResourceDictionary绑定两者的事实.我想我也可以在DataContextChanged事件中做到这一点,但是有更好的方法吗?
解决方法
如果只是为了几个动画我会建议使用Visual States.然后,您可以在视图上使用GoToAction行为来触发不同的动画.如果您正在处理许多类似的动画,那么创建自己的行为将是一个更好的解决方案.
更新
我已经创建了一个非常简单的行为来给Rectangle一个小的颜色动画.这是代码.
public class ColorAnimationBehavior : TriggerAction<FrameworkElement> { #region Fill color [Description("The background color of the rectangle")] public Color FillColor { get { return (Color)GetValue(FillColorProperty); } set { SetValue(FillColorProperty,value); } } public static readonly DependencyProperty FillColorProperty = DependencyProperty.Register("FillColor",typeof(Color),typeof(ColorAnimationBehavior),null); #endregion protected override void Invoke(object parameter) { var rect = (Rectangle)AssociatedObject; var sb = new Storyboard(); sb.Children.Add(CreateVisibilityAnimation(rect,new Duration(new TimeSpan(0,1)),FillColor)); sb.Begin(); } private static ColorAnimationUsingKeyFrames CreateVisibilityAnimation(DependencyObject element,Duration duration,Color color) { var animation = new ColorAnimationUsingKeyFrames(); animation.KeyFrames.Add(new SplineColorKeyFrame { KeyTime = new TimeSpan(duration.TimeSpan.Ticks),Value = color }); Storyboard.SetTargetProperty(animation,new PropertyPath("(Shape.Fill).(SolidColorBrush.Color)")); Storyboard.SetTarget(animation,element); return animation; } }
在xaml中,您只需附加此行为,
<Rectangle x:Name="rectangle" Fill="Black" Margin="203,103,217,227" Stroke="Black"> <i:Interaction.Triggers> <i:EventTrigger EventName="MouseLeftButtonDown"> <local:ColorAnimationBehavior FillColor="Red"/> </i:EventTrigger> </i:Interaction.Triggers> </Rectangle>
单击矩形时,它应从黑色变为红色.