I'm trying to start a storyboard animation from my viewmodel. The idea is that there is an animation every time my application receives a position update from a server later on, but for now it would be fine to have a proof of concept where I can update the position and start the animation by pressing a button.
My first approach was to use Microsoft.Expression.Interactivity ControlStoryboardAction (Feel free to tell me if there is a better approach for what I want to achieve). I'm binding the trigger to the CanAnimate Property, which is set to true by default, so the animation should start right after loading - but it doesn't. The storyboard works when I use an Eventtrigger, but this is not what I want:
<Window x:Class="AnimationExample.MainWindow"
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:local="clr-namespace:AnimationExample"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<local:MainWindowViewModel />
</Window.DataContext>
<Canvas Name="CanvasWrapper" Width="525" Height="350">
<Ellipse Fill="Red" Width="60" Height="60" Canvas.Left="60" Canvas.Top="60">
<Ellipse.Resources>
<Storyboard x:Key="Movement">
<DoubleAnimation
Storyboard.TargetProperty="(Canvas.Left)"
Duration="0:0:0.1" To="{Binding NextPosX}" />
<DoubleAnimation
Storyboard.TargetProperty="(Canvas.Top)"
Duration="0:0:0.1" To="{Binding NextPosY}" />
</Storyboard>
</Ellipse.Resources>
<!-- This trigger is just for testing and works fine! -->
<Ellipse.Triggers>
<EventTrigger RoutedEvent="Ellipse.MouseEnter">
<EventTrigger.Actions>
<BeginStoryboard Storyboard="{StaticResource Movement}"/>
</EventTrigger.Actions>
</EventTrigger>
</Ellipse.Triggers>
<!-- This trigger doesn't works -->
<i:Interaction.Triggers>
<ei:DataTrigger Binding="{Binding CanAnimate}" Value="True" Comparison="Equal">
<ei:ControlStoryboardAction Storyboard="{StaticResource Movement}" ControlStoryboardOption="Play" />
</ei:DataTrigger>
</i:Interaction.Triggers>
</Ellipse>
</Canvas>
</Window>
This is my viewmodel so far. Obviously the Binding to the ActionCommand is missing, and the ActionCommand should also change the CanAnimate so that the Animation is triggered again, but it should still animate one time due to CanAnimate being true:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
namespace AnimationExample
{
class MainWindowViewModel : INotifyPropertyChanged
{
int _nextPosX = 120;
public int NextPosX
{
get { return _nextPosX; }
set
{
if (value != _nextPosX)
{
_nextPosX = value;
OnPropertyChanged("NextPosX");
}
}
}
int _nextPosY = 120;
public int NextPosY
{
get { return _nextPosY; }
set
{
if (value != _nextPosY)
{
_nextPosY = value;
OnPropertyChanged("NextPosY");
}
}
}
bool _canAnimate = true;
public bool CanAnimate
{
get { return _canAnimate; }
set
{
if (value != _canAnimate)
{
_canAnimate = value;
OnPropertyChanged("CanAnimate");
}
}
}
ICommand _calculate;
public ICommand CalculateNextPos
{
get
{
if(_calculate == null)
{
_calculate = new ActionCommand(dummy =>
{
NextPosX = 500;
NextPosY = 500;
}, dummy => true);
}
return _calculate;
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}
Thanks in advance!