I used the code published by Xin and made some very small tweaks (code below). The only 3 significant differences:
I created a behavior to work with any UIElement, not just a rectangle
I used PropertyChangedTrigger instead of EventTrigger. This allows me to track the color property in the ViewModel instead of listening for click events.
I bound the FillColor property to the Color ViewModel property.
To use this, you need to download the Blend 4 SDK (it's free, and you only need it if you don't have Expression Blend yet) and add links to System.Windows.Interactivity and Microsoft.Expression.Interactions
Here is the code for the behavior class:
// complete code for the animation behavior using System.Windows; using System.Windows.Interactivity; using System.Windows.Media; using System.Windows.Media.Animation; namespace ColorAnimationBehavior { public class ColorAnimationBehavior: TriggerAction<UIElement> { 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); public Duration Duration { get { return (Duration)GetValue(DurationProperty); } set { SetValue(DurationProperty, value); } } // Using a DependencyProperty as the backing store for Duration. This enables animation, styling, binding, etc... public static readonly DependencyProperty DurationProperty = DependencyProperty.Register("Duration", typeof(Duration), typeof(ColorAnimationBehavior), null); protected override void Invoke(object parameter) { var storyboard = new Storyboard(); storyboard.Children.Add(CreateColorAnimation(this.AssociatedObject, this.Duration, this.FillColor)); storyboard.Begin(); } private static ColorAnimationUsingKeyFrames CreateColorAnimation(UIElement element, Duration duration, Color color) { var animation = new ColorAnimationUsingKeyFrames(); animation.KeyFrames.Add(new SplineColorKeyFrame() { KeyTime = duration.TimeSpan, Value = color }); Storyboard.SetTargetProperty(animation, new PropertyPath("(Shape.Fill).(SolidColorBrush.Color)")); Storyboard.SetTarget(animation, element); return animation; } } }
// complete code for the animation behavior using System.Windows; using System.Windows.Interactivity; using System.Windows.Media; using System.Windows.Media.Animation; namespace ColorAnimationBehavior { public class ColorAnimationBehavior: TriggerAction<UIElement> { 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); public Duration Duration { get { return (Duration)GetValue(DurationProperty); } set { SetValue(DurationProperty, value); } } // Using a DependencyProperty as the backing store for Duration. This enables animation, styling, binding, etc... public static readonly DependencyProperty DurationProperty = DependencyProperty.Register("Duration", typeof(Duration), typeof(ColorAnimationBehavior), null); protected override void Invoke(object parameter) { var storyboard = new Storyboard(); storyboard.Children.Add(CreateColorAnimation(this.AssociatedObject, this.Duration, this.FillColor)); storyboard.Begin(); } private static ColorAnimationUsingKeyFrames CreateColorAnimation(UIElement element, Duration duration, Color color) { var animation = new ColorAnimationUsingKeyFrames(); animation.KeyFrames.Add(new SplineColorKeyFrame() { KeyTime = duration.TimeSpan, Value = color }); Storyboard.SetTargetProperty(animation, new PropertyPath("(Shape.Fill).(SolidColorBrush.Color)")); Storyboard.SetTarget(animation, element); return animation; } } }
Now here is the XAML that anchors it to your rectangle:
<UserControl x:Class="MVVM.ColorAnimation.Silverlight.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:ColorAnimation="clr-namespace:MVVM.ColorAnimation" xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions" xmlns:ca="clr-namespace:ColorAnimationBehavior;assembly=ColorAnimationBehavior" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="400"> <UserControl.DataContext> <ColorAnimation:MainWindowViewModel /> </UserControl.DataContext> <Grid> <Grid.RowDefinitions> <RowDefinition Height="*" /> <RowDefinition Height="40" /> </Grid.RowDefinitions> <Rectangle x:Name="rectangle" Margin="10" Stroke="Black" Fill="Red"> <i:Interaction.Triggers> <ei:PropertyChangedTrigger Binding="{Binding Color}"> <ca:ColorAnimationBehavior FillColor="{Binding Color}" Duration="0:0:0.5" /> </ei:PropertyChangedTrigger> </i:Interaction.Triggers> </Rectangle> <StackPanel Orientation="Horizontal" Grid.Row="1"> <Button Command="{Binding BlueCommand}" Width="100" Content="Blue"/> <Button Command="{Binding GreenCommand}" Width="100" Content="Green"/> </StackPanel> </Grid> </UserControl>
<UserControl x:Class="MVVM.ColorAnimation.Silverlight.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:ColorAnimation="clr-namespace:MVVM.ColorAnimation" xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions" xmlns:ca="clr-namespace:ColorAnimationBehavior;assembly=ColorAnimationBehavior" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="400"> <UserControl.DataContext> <ColorAnimation:MainWindowViewModel /> </UserControl.DataContext> <Grid> <Grid.RowDefinitions> <RowDefinition Height="*" /> <RowDefinition Height="40" /> </Grid.RowDefinitions> <Rectangle x:Name="rectangle" Margin="10" Stroke="Black" Fill="Red"> <i:Interaction.Triggers> <ei:PropertyChangedTrigger Binding="{Binding Color}"> <ca:ColorAnimationBehavior FillColor="{Binding Color}" Duration="0:0:0.5" /> </ei:PropertyChangedTrigger> </i:Interaction.Triggers> </Rectangle> <StackPanel Orientation="Horizontal" Grid.Row="1"> <Button Command="{Binding BlueCommand}" Width="100" Content="Blue"/> <Button Command="{Binding GreenCommand}" Width="100" Content="Green"/> </StackPanel> </Grid> </UserControl>
It was an Xin idea - I cleaned it a bit.