I am trying to adapt a simple WPF application to use the Model-View-ViewModel pattern. On my page I have a couple of animations:
<Page.Resources>
<Storyboard x:Name="storyboardRight"
x:Key="storyboardRight">
<DoubleAnimation x:Name="da3"
Storyboard.TargetName="labelRight"
Storyboard.TargetProperty="Opacity"
From="0"
To="1"
Duration="0:0:0.5" />
<DoubleAnimation x:Name="da4"
Storyboard.TargetName="labelRight"
Storyboard.TargetProperty="Opacity"
From="1"
To="0"
BeginTime="0:0:1"
Duration="0:0:0.5" />
</Storyboard>
...
</Page.Resources>
Currently I begin the animation in the code behind, and can listen to the Completed event to do something when it finishes with the following code:
storyboardRight = (Storyboard)TryFindResource("storyboardRight");
storyboardRight.Completed += new EventHandler(storyboardRight_Completed);
storyboardRight.Begin(this);
Is there a way of data binding the storyboard to my ViewModel so that it starts on an event raised by the ViewModel and can call-back into that ViewModel when it is finished?
I had the opportunity to put this question to Microsoft's Josh Twist, who kindly took the time to provide an answer to this problem. The solution is to use a DataTrigger
in combination with an enum in the ViewModel to launch the Storyboard, and this in turn requires putting the page into a ContentPresenter
. To handle animation completion, a small amount of code behind was required to make a call into an ICommand
on the ViewModel.
Read Josh's post here for a full description of the solution.
I did this by a using DataTrigger and binding it to a property in my ViewModel. When the "FlashingBackGround" property gets set to "ON" the Storyboard animation starts.
Also make sure to include in your project a reference to "Microsoft.Expression.Interactions"
XAML: (this goes directly in the root node)
<Window
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
x:Name="window" >
...
<i:Interaction.Triggers>
<ei:DataTrigger Binding="{Binding FlashingBackground, Mode=OneWay}" Value="ON">
<ei:ControlStoryboardAction Storyboard="{StaticResource MyAnimation}"
ControlStoryboardOption="Play"/>
</ei:DataTrigger>
</i:Interaction.Triggers>
...
</Window>
ViewModel:
private void TurnOnFlashingBackround()
{
this.FlashingBackground = "ON";
}
private string _FlashingBackround = "OFF";
public string FlashingBackground
{
get { return this._FlashingBackround; }
private set
{
if (this.FlashingBackground == value)
{
return;
}
this._FlashingBackround = value;
this.OnPropertyChanged("FlashingBackground");
}
}
public new event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(
this,
new PropertyChangedEventArgs(propertyName));
}
}
Finally, the Viewmodel must inherit from "INotifyPropertyChanged"
You need to use an EventTrigger
. This article about Animations in WPF might help. See also the Routed Events Overview on the MSDN and How to: Use Event Triggers to Control a Storyboard After It Starts.