I have an image of a fish in a WPF project (VB.net code behind), and I'm attempting to animate it swimming back and forth using two transforms.
For some reason, while if I only animate the ScaleTransform (with ScaleTransform alone, and no TransformGroup), the animation works fine, the TranslateTransform animation does not. Additionally, the ScaleTransform does not work when inside the TransformGroup.
Here is the code I'm using. What am I doing wrong?
<Image Height="90" HorizontalAlignment="Left" Name="Fish1" Stretch="Fill" VerticalAlignment="Top" Width="260" Source="/VBP-WORD4WORD;component/Images/IMG-FISH1.png" Canvas.Left="24" Canvas.Top="67" Margin="-28,70,0,0">
<Image.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleX="1"/>
<TranslateTransform X="0"/>
</TransformGroup>
</Image.RenderTransform>
<Image.Triggers>
<EventTrigger RoutedEvent="Image.Loaded">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimationUsingKeyFrames Duration="0:0:30" Storyboard.TargetProperty="RenderTransform.(TransformGroup.TranslateTransform.X)" RepeatBehavior="Forever">
<LinearDoubleKeyFrame KeyTime="0:0:0" Value="0"/>
<LinearDoubleKeyFrame KeyTime="0:0:14.9" Value="407"/>
<LinearDoubleKeyFrame KeyTime="0:0:15" Value="680"/>
<LinearDoubleKeyFrame KeyTime="0:0:29.9" Value="265"/>
<LinearDoubleKeyFrame KeyTime="0:0:30" Value="0"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Duration="0:0:30" Storyboard.TargetProperty="RenderTransform.(TransformGroup.ScaleTransform.ScaleX)" RepeatBehavior="Forever">
<LinearDoubleKeyFrame KeyTime="0:0:14.9" Value="1"/>
<LinearDoubleKeyFrame KeyTime="0:0:15" Value="-1"/>
<LinearDoubleKeyFrame KeyTime="0:0:29.9" Value="-1"/>
<LinearDoubleKeyFrame KeyTime="0:0:30" Value="1"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Image.Triggers>
</Image>
Those property paths are all wrong, but i would vote for just avoiding the whole trouble of only using those paths by utilizing Storyboard.TargetName; this works:
<!-- ... -->
<TransformGroup>
<ScaleTransform x:Name="scaleTransform" ScaleX="1"/>
<TranslateTransform x:Name="translateTransform" X="0"/>
</TransformGroup>
<!-- ... -->
<Storyboard>
<DoubleAnimationUsingKeyFrames Duration="0:0:30"
Storyboard.TargetProperty="ScaleX"
Storyboard.TargetName="scaleTransform"
RepeatBehavior="Forever">
<LinearDoubleKeyFrame KeyTime="0:0:14.9" Value="1"/>
<LinearDoubleKeyFrame KeyTime="0:0:15" Value="-1"/>
<LinearDoubleKeyFrame KeyTime="0:0:29.9" Value="-1"/>
<LinearDoubleKeyFrame KeyTime="0:0:30" Value="1"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Duration="0:0:30"
Storyboard.TargetProperty="X"
Storyboard.TargetName="translateTransform"
RepeatBehavior="Forever">
<LinearDoubleKeyFrame KeyTime="0:0:0" Value="0"/>
<LinearDoubleKeyFrame KeyTime="0:0:14.9" Value="407"/>
<LinearDoubleKeyFrame KeyTime="0:0:15" Value="680"/>
<LinearDoubleKeyFrame KeyTime="0:0:29.9" Value="265"/>
<LinearDoubleKeyFrame KeyTime="0:0:30" Value="0"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
If you really want to do it using Storyboard.TargetProperty only, these would be the correct paths as i found out just now:
Storyboard.TargetProperty="RenderTransform.Children[0].ScaleX"
Storyboard.TargetProperty="RenderTransform.Children[1].X"
Which does make perfect sense if you think about it.
Related
I have a TextBlock which displays an image from a font.
I want the TextBlock to pulsate when a boolean flag is set in the ViewModel.
I found the Answer given by Chris W in this similar Stackoverflow question. The second box in his example is just what I want. The pulsating example is basically:
<Storyboard x:Key="Pulse">
<DoubleAnimationUsingKeyFrames
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)"
Storyboard.TargetName="PulseBox"
>
<EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="1.15"/>
<EasingDoubleKeyFrame KeyTime="0:0:1" Value="1"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)"
Storyboard.TargetName="PulseBox"
>
<EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="1.15"/>
<EasingDoubleKeyFrame KeyTime="0:0:1" Value="1"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
As I knowing nothing about triggers and Storyboards in WPF, I gave it a try to put this in a DataTrigger but failed big time.
I came up with this:
<TextBlock Text="SomeCodeToAImageInAFont" Background="CornflowerBlue">
<TextBlock.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding Activate}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimationUsingKeyFrames
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)"
>
<EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="1.15"/>
<EasingDoubleKeyFrame KeyTime="0:0:1" Value="1"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)"
>
<EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="1.15"/>
<EasingDoubleKeyFrame KeyTime="0:0:1" Value="1"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
Activate is a boolean property in the ViewModel.
When I set the Activate bool to True I get this exception:
System.InvalidOperationException
The property [Unknown] does not point to a DependencyObject in the path (0).(1)[0].(2).
It's quite clear that these lines are incorrect:
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)"
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)"
Unfortunately I don't understand the exception and how to fix it.
Any suggestions?
Since you access a transformation RenderTransform in your animation, you have to add it to the element. I also changed RepeatBehavior to do execution 10 times, or you can set it to RepeatBehavior="Forever".
<TextBlock Text="SomeCodeToAImageInAFont" Background="CornflowerBlue">
<TextBlock.RenderTransform>
<TransformGroup>
<ScaleTransform/>
</TransformGroup>
</TextBlock.RenderTransform>
<TextBlock.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding Activate}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimationUsingKeyFrames RepeatBehavior="10x"
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)"
>
<EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="1.15"/>
<EasingDoubleKeyFrame KeyTime="0:0:1" Value="1"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames RepeatBehavior="10x"
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)"
>
<EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="1.15"/>
<EasingDoubleKeyFrame KeyTime="0:0:1" Value="1"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
I'm trying to create a marching dot animation where there's a series of small circles and one will grow a bit and change color, then the next will, and so on, and this will bounce back and forth. The animation will be triggered by a bool value in the ViewModel.
I actually had this working before deciding to use the MVVM pattern, it was easy: I had the storyboard in the Page.Resources tags and called the animation from code behind on button click. Now I'm stuck with this decoupled, it seems no matter what I try there's always an error of some kind.
Here's the dots in xaml:
<Grid Grid.Row="4" Grid.Column="3" Grid.ColumnSpan="2" Margin="20">
<Grid.RowDefinitions>
<RowDefinition Height="2*"/>
<RowDefinition Height="1*"/>
<RowDefinition Height="2*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Ellipse Name="Dot5" Grid.Row="1" Grid.Column="0" Style="{StaticResource ConnectionMeterOff}"/>
<Ellipse Name="Dot4" Grid.Row="1" Grid.Column="1" Style="{StaticResource ConnectionMeterOff}"/>
<Ellipse Name="Dot3" Grid.Row="1" Grid.Column="2" Style="{StaticResource ConnectionMeterOff}"/>
<Ellipse Name="Dot2" Grid.Row="1" Grid.Column="3" Style="{StaticResource ConnectionMeterOff}"/>
<Ellipse Name="Dot1" Grid.Row="1" Grid.Column="4" Style="{StaticResource ConnectionMeterOff}"/>
</Grid>
And my current animation:
<DataTemplate x:Key="MarchingDots">
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding IsConnecting}" Value="true">
<DataTrigger.EnterActions>
<BeginStoryboard Name="MarchingDotsAnimation">
<Storyboard RepeatBehavior="Forever" AutoReverse="True">
<DoubleAnimation Storyboard.TargetName="Dot1" BeginTime="0:0:0.1"
Storyboard.TargetProperty="Width" From="10" To="15"
Duration="0:0:0.2" AutoReverse="True"/>
<ColorAnimation Storyboard.TargetName="Dot1" BeginTime="0:0:0.1"
Storyboard.TargetProperty="(Ellipse.Fill).(SolidColorBrush.Color)"
From="#FF5B5B5B" To="#FF84161C" Duration="0:0:0.3" AutoReverse="True"/>
<DoubleAnimation Storyboard.TargetName="Dot2" BeginTime="0:0:0.2"
Storyboard.TargetProperty="Width" From="10" To="15"
Duration="0:0:0.2" AutoReverse="True"/>
<ColorAnimation Storyboard.TargetName="Dot2" BeginTime="0:0:0.2"
Storyboard.TargetProperty="(Ellipse.Fill).(SolidColorBrush.Color)"
From="#FF5B5B5B" To="#FF84161C" Duration="0:0:0.3" AutoReverse="True"/>
<DoubleAnimation Storyboard.TargetName="Dot3" BeginTime="0:0:0.3"
Storyboard.TargetProperty="Width" From="10" To="15"
Duration="0:0:0.2" AutoReverse="True"/>
<ColorAnimation Storyboard.TargetName="Dot3" BeginTime="0:0:0.3"
Storyboard.TargetProperty="(Ellipse.Fill).(SolidColorBrush.Color)"
From="#FF5B5B5B" To="#FF84161C" Duration="0:0:0.3" AutoReverse="True"/>
<DoubleAnimation Storyboard.TargetName="Dot4" BeginTime="0:0:0.4"
Storyboard.TargetProperty="Width" From="10" To="15"
Duration="0:0:0.2" AutoReverse="True"/>
<ColorAnimation Storyboard.TargetName="Dot4" BeginTime="0:0:0.4"
Storyboard.TargetProperty="(Ellipse.Fill).(SolidColorBrush.Color)"
From="#FF5B5B5B" To="#FF84161C" Duration="0:0:0.3" AutoReverse="True"/>
<DoubleAnimation Storyboard.TargetName="Dot5" BeginTime="0:0:0.5"
Storyboard.TargetProperty="Width" From="10" To="15"
Duration="0:0:0.2" AutoReverse="True"/>
<ColorAnimation Storyboard.TargetName="Dot5" BeginTime="0:0:0.5"
Storyboard.TargetProperty="(Ellipse.Fill).(SolidColorBrush.Color)"
From="#FF5B5B5B" To="#FF84161C" Duration="0:0:0.3" AutoReverse="True"/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
I'm pretty sure my issue isn't the binding, but either that the animation isn't attached to the dots, or how I'm trying to wrap it to get access to the triggers. If I keep it just a Storyboard like before, I don't have anything to trigger it. If I try a style, it complains that I can use "Storyboard.TargetName". I've also tried EventTriggers. And copious amounts of Googling...all the examples seem to be single elements (like a rectangle) where the storyboard can be attached to the element's style.
I'm sure this is simple, but what am I doing wrong?
This needs a bit of cleanup, but it will get you started. First declare your animations:
<Storyboard x:Key="Storyboard1" RepeatBehavior="Forever">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)">
<EasingDoubleKeyFrame KeyTime="0:0:0" Value="1"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.25" Value="1.15"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="1"/>
<EasingDoubleKeyFrame KeyTime="0:0:1.5" Value="1"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)">
<EasingDoubleKeyFrame KeyTime="0:0:0" Value="1"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.25" Value="1.15"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="1"/>
<EasingDoubleKeyFrame KeyTime="0:0:1.5" Value="1"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
<Storyboard x:Key="Storyboard2" RepeatBehavior="Forever">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)">
<EasingDoubleKeyFrame KeyTime="0:0:0" Value="1"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.25" Value="1"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="1.15"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.75" Value="1"/>
<EasingDoubleKeyFrame KeyTime="0:0:1.5" Value="1"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)">
<EasingDoubleKeyFrame KeyTime="0:0:0" Value="1"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.25" Value="1"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="1.15"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.75" Value="1"/>
<EasingDoubleKeyFrame KeyTime="0:0:1.5" Value="1"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
<Storyboard x:Key="Storyboard3" RepeatBehavior="Forever">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)">
<EasingDoubleKeyFrame KeyTime="0:0:0" Value="1"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="1"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.75" Value="1.15"/>
<EasingDoubleKeyFrame KeyTime="0:0:1.0" Value="1"/>
<EasingDoubleKeyFrame KeyTime="0:0:1.5" Value="1"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)">
<EasingDoubleKeyFrame KeyTime="0:0:0" Value="1"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="1"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.75" Value="1.15"/>
<EasingDoubleKeyFrame KeyTime="0:0:1.0" Value="1"/>
<EasingDoubleKeyFrame KeyTime="0:0:1.5" Value="1"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
<Storyboard x:Key="Storyboard4" RepeatBehavior="Forever">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)">
<EasingDoubleKeyFrame KeyTime="0:0:0" Value="1"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.75" Value="1"/>
<EasingDoubleKeyFrame KeyTime="0:0:1.0" Value="1.15"/>
<EasingDoubleKeyFrame KeyTime="0:0:1.25" Value="1"/>
<EasingDoubleKeyFrame KeyTime="0:0:1.5" Value="1"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)">
<EasingDoubleKeyFrame KeyTime="0:0:0" Value="1"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.75" Value="1"/>
<EasingDoubleKeyFrame KeyTime="0:0:1.0" Value="1.15"/>
<EasingDoubleKeyFrame KeyTime="0:0:1.25" Value="1"/>
<EasingDoubleKeyFrame KeyTime="0:0:1.5" Value="1"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
<Storyboard x:Key="Storyboard5" RepeatBehavior="Forever">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)">
<EasingDoubleKeyFrame KeyTime="0:0:0" Value="1"/>
<EasingDoubleKeyFrame KeyTime="0:0:1.0" Value="1"/>
<EasingDoubleKeyFrame KeyTime="0:0:1.25" Value="1.15"/>
<EasingDoubleKeyFrame KeyTime="0:0:1.5" Value="1"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)">
<EasingDoubleKeyFrame KeyTime="0:0:0" Value="1"/>
<EasingDoubleKeyFrame KeyTime="0:0:1.0" Value="1"/>
<EasingDoubleKeyFrame KeyTime="0:0:1.25" Value="1.15"/>
<EasingDoubleKeyFrame KeyTime="0:0:1.5" Value="1"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
I'm going to build it out of ellipses, so create a base style for them:
<Style x:Key="EllipseStyle" TargetType="Ellipse">
<Setter Property="Fill" Value="Black" />
<Setter Property="Width" Value="32" />
<Setter Property="Height" Value="32" />
<Setter Property="RenderTransformOrigin" Value="0.5,0.5" />
<Setter Property="Margin" Value="10" />
<Setter Property="RenderTransform">
<Setter.Value>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform/>
<TranslateTransform/>
</TransformGroup>
</Setter.Value>
</Setter>
</Style>
Then create five ellipses, assign each one it's corresponding storyboard and use a DataTrigger to turn the animation on and off:
<UniformGrid Columns="5">
<Ellipse>
<Ellipse.Style>
<Style TargetType="Ellipse" BasedOn="{StaticResource EllipseStyle}">
<Style.Triggers>
<DataTrigger Binding="{Binding Animating}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard Name="Storyboard1" Storyboard="{StaticResource Storyboard1}" />
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<StopStoryboard BeginStoryboardName="Storyboard1" />
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Ellipse.Style>
</Ellipse>
<Ellipse>
<Ellipse.Style>
<Style TargetType="Ellipse" BasedOn="{StaticResource EllipseStyle}">
<Style.Triggers>
<DataTrigger Binding="{Binding Animating}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard Name="Storyboard2" Storyboard="{StaticResource Storyboard2}" />
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<StopStoryboard BeginStoryboardName="Storyboard2" />
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Ellipse.Style>
</Ellipse>
<Ellipse>
<Ellipse.Style>
<Style TargetType="Ellipse" BasedOn="{StaticResource EllipseStyle}">
<Style.Triggers>
<DataTrigger Binding="{Binding Animating}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard Name="Storyboard3" Storyboard="{StaticResource Storyboard3}" />
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<StopStoryboard BeginStoryboardName="Storyboard3" />
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Ellipse.Style>
</Ellipse>
<Ellipse>
<Ellipse.Style>
<Style TargetType="Ellipse" BasedOn="{StaticResource EllipseStyle}">
<Style.Triggers>
<DataTrigger Binding="{Binding Animating}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard Name="Storyboard4" Storyboard="{StaticResource Storyboard4}" />
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<StopStoryboard BeginStoryboardName="Storyboard4" />
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Ellipse.Style>
</Ellipse>
<Ellipse>
<Ellipse.Style>
<Style TargetType="Ellipse" BasedOn="{StaticResource EllipseStyle}">
<Style.Triggers>
<DataTrigger Binding="{Binding Animating}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard Name="Storyboard5" Storyboard="{StaticResource Storyboard5}" />
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<StopStoryboard BeginStoryboardName="Storyboard5" />
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Ellipse.Style>
</Ellipse>
</UniformGrid>
<CheckBox Content="Animate" IsChecked="{Binding Animating}" HorizontalAlignment="Center"/>
</StackPanel>
I'm assuming there's a property in your view model called Animating that you're using to control this, I've added a checkbox to this code as well for testing:
EDIT: just updated the animations to get rid of that flicker on the right.
I want to make an image flash a set number of times, when I set its Visibility to Visible. And when it's finished flashing, I want it to make itself Collapsed again.
Here's a simple version of what I'm trying to do:
<Image Visibility="Collapsed"
Margin="0,0,3,0"
Width="24"
Source="blah"
Height="24">
<Image.Style>
<Style TargetType="{x:Type Image}">
<Style.Triggers>
<Trigger Property="Visibility"
Value="Visible">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard RepeatBehavior="5x"
x:Name="flashingStoryboard">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="Opacity"
Duration="0:0:1"
FillBehavior="Stop">
<DiscreteDoubleKeyFrame Value="0"
KeyTime="0:0:0" />
<DiscreteDoubleKeyFrame Value="1"
KeyTime="0:0:0.5" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
</Trigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
Can I do this in XAML?
If you know how many times it will be flashed then you can set BeginTime correspondingly the number of times your flashing comes along.
<BeginStoryboard>
<Storyboard>
<DoubleAnimationUsingKeyFrames RepeatBehavior="5x" Storyboard.TargetProperty="Opacity" Duration="0:0:1">
<DiscreteDoubleKeyFrame Value="0" KeyTime="0:0:0" />
<DiscreteDoubleKeyFrame Value="1" KeyTime="0:0:0.5" />
</DoubleAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames BeginTime="0:0:5" Duration="0:0:0" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame Value="{x:Static Visibility.Collapsed}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
I have a combobox, which is bound to an enumeration of animations. We have the requirement such that if an animation style is selected in the combo box, the corresponding animation should be triggered on a textblock. i have 3 animations, namely fade, scale and blink. While blink is working fine, fade and scale doesnt work. it works only for the first time when the screen loads and then thereafter, even if the selection is changed to fade/scale, teh animation is not triggered. As if now, i have triggered the animation using a data trigger, and that is when this issue started coming, but the animation was triggered perfectly when we tried to use an event trigger. My code is as below. Could someone help me as to what is it that I am doing wrong and how it can be rectified.
Animations:
<Storyboard x:Key="Fade">
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)">
<DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Visible}"/>
</ObjectAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)">
<EasingDoubleKeyFrame KeyTime="0" Value="0"/>
<EasingDoubleKeyFrame KeyTime="0:0:2" Value="1"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
<Storyboard x:Key="Scale">
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)">
<DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Visible}"/>
</ObjectAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)">
<EasingDoubleKeyFrame KeyTime="0" Value="1"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.7" Value="1"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)">
<EasingDoubleKeyFrame KeyTime="0" Value="0"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.7" Value="1"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)">
<EasingDoubleKeyFrame KeyTime="0" Value="0"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.7" Value="1"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
<Storyboard x:Key="Blink">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)">
<EasingDoubleKeyFrame KeyTime="0" Value="1"/>
</DoubleAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames RepeatBehavior="3x" Storyboard.TargetProperty="(UIElement.Visibility)">
<DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Visible}"/>
<DiscreteObjectKeyFrame KeyTime="0:0:0.25" Value="{x:Static Visibility.Collapsed}"/>
<DiscreteObjectKeyFrame KeyTime="0:0:0.5" Value="{x:Static Visibility.Visible}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
The combobox, textblock and data triggers used to trigger the animation:
<telerik:RadComboBox x:Name="animationTypeComboBox"
Foreground="White"
Width="180"
ItemsSource="{Binding Source={StaticResource AnimationTypeEnumValues}}"
SelectedItem="{Binding SelectedAnimationType, Mode=TwoWay, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}"
VerticalAlignment="Center" >
</telerik:RadComboBox>
<TextBlock x:Name="testMsg" Text="Test message" VerticalAlignment="Center" HorizontalAlignment="Center" RenderTransformOrigin="0.5,0.5">
<TextBlock.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform/>
<TranslateTransform/>
</TransformGroup>
</TextBlock.RenderTransform>
<TextBlock.Style>
<Style TargetType="TextBlock" BasedOn="{StaticResource Subheading}">
<Style.Triggers>
<DataTrigger Binding="{Binding SelectedAnimationType}" Value="{x:Static ent:AnimationType.Fade}">
<DataTrigger.EnterActions>
<BeginStoryboard Storyboard="{StaticResource Fade}"/>
</DataTrigger.EnterActions>
</DataTrigger>
<DataTrigger Binding="{Binding SelectedAnimationType}" Value="{x:Static ent:AnimationType.Scale}">
<DataTrigger.EnterActions>
<BeginStoryboard Storyboard="{StaticResource Scale}"/>
</DataTrigger.EnterActions>
</DataTrigger>
<DataTrigger Binding="{Binding SelectedAnimationType}" Value="{x:Static ent:AnimationType.Blink}">
<DataTrigger.EnterActions>
<BeginStoryboard Storyboard="{StaticResource Blink}"/>
</DataTrigger.EnterActions>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
I made few changes in your code to make it work in my local system.... here is a solution to your problem..
<TextBlock x:Name="testMsg" Text="Test message" VerticalAlignment="Center" HorizontalAlignment="Center" RenderTransformOrigin="0.5,0.5">
<TextBlock.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform/>
<TranslateTransform/>
</TransformGroup>
</TextBlock.RenderTransform>
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
<DataTrigger Binding="{Binding SelectedItem,ElementName=AnimStyles}" Value="Fade">
<DataTrigger.EnterActions>
<RemoveStoryboard BeginStoryboardName="Scale"/>
<RemoveStoryboard BeginStoryboardName="Blink"/>
<BeginStoryboard Name="Fade">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)">
<DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Visible}"/>
</ObjectAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)">
<EasingDoubleKeyFrame KeyTime="0" Value="0"/>
<EasingDoubleKeyFrame KeyTime="0:0:2" Value="1"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
<DataTrigger Binding="{Binding SelectedItem,ElementName=AnimStyles}" Value="Scale">
<DataTrigger.EnterActions>
<RemoveStoryboard BeginStoryboardName="Fade"/>
<RemoveStoryboard BeginStoryboardName="Blink"/>
<BeginStoryboard Name="Scale">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)">
<DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Visible}"/>
</ObjectAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)">
<EasingDoubleKeyFrame KeyTime="0" Value="1"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.7" Value="1"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)">
<EasingDoubleKeyFrame KeyTime="0" Value="0"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.7" Value="1"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)">
<EasingDoubleKeyFrame KeyTime="0" Value="0"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.7" Value="1"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
<DataTrigger Binding="{Binding SelectedItem,ElementName=AnimStyles}" Value="Blink">
<DataTrigger.EnterActions>
<RemoveStoryboard BeginStoryboardName="Fade"/>
<RemoveStoryboard BeginStoryboardName="Scale"/>
<BeginStoryboard Name="Blink">
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)">
<EasingDoubleKeyFrame KeyTime="0" Value="1"/>
</DoubleAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames RepeatBehavior="3x" Storyboard.TargetProperty="(UIElement.Visibility)">
<DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Visible}"/>
<DiscreteObjectKeyFrame KeyTime="0:0:0.25" Value="{x:Static Visibility.Collapsed}"/>
<DiscreteObjectKeyFrame KeyTime="0:0:0.5" Value="{x:Static Visibility.Visible}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
In the above code instead of taking story boards in resources i am taking then in line... and removing the other storyboards before starting the actual storyboard...
This means what ever be the behavior effected by the previous Storyboards will be removed and every time animation works as like a new one..
I have the following code in a WPF 4 project, linked to an imagebox. I have four other similar instances of it that work perfectly. Why is this one throwing that vague "BAML" error we all hate (it points to the animations)? FYI, I'm using VB.net in code behind.
<Image Height="121" HorizontalAlignment="Left" Margin="139,83,0,0" Name="Spinefish" Stretch="Fill" VerticalAlignment="Top" Width="323" Source="/VBP-WORD4WORD;component/Images/IMG-SPINEFISH1.png">
<Image.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleX="1" />
<TranslateTransform X="0" />
</TransformGroup>
</Image.RenderTransform>
<Image.Triggers>
<EventTrigger RoutedEvent="FrameworkElement.Loaded">
<BeginStoryboard>
<BeginStoryboard.Storyboard>
<Storyboard>
<DoubleAnimationUsingKeyFrames Duration="0:0:60" RepeatBehavior="Forever" Storyboard.TargetProperty="RenderTransform.Children[1].X">
<LinearDoubleKeyFrame KeyTime="0:0:0" Value="-1000" />
<LinearDoubleKeyFrame KeyTime="0:0:25" Value="-1000" />
<LinearDoubleKeyFrame KeyTime="0:0:30" Value="1000" />
<LinearDoubleKeyFrame KeyTime="0:0:55" Value="1000" />
<LinearDoubleKeyFrame KeyTime="0:0:60" Value="-1000" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Duration="0:0:60" RepeatBehavior="Forever" Storyboard.TargetProperty="RenderTransform.Children[0].ScaleX">
<LinearDoubleKeyFrame KeyTime="0:0:29.9" Value="1" />
<LinearDoubleKeyFrame KeyTime="0:0:30" Value="-1" />
<LinearDoubleKeyFrame KeyTime="0:0:59.9" Value="-1" />
<LinearDoubleKeyFrame KeyTime="0:0:60" Value="1" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard.Storyboard>
</BeginStoryboard>
</EventTrigger>
</Image.Triggers>
</Image>
KeyTime="0:0:60" and Duration="0:0:60" do not exist, the seconds range is from 0 to 59 only, change those to 0:1:0.