WPF Animated UserControl - Canvas - wpf

In developing for my project I am trying to create a usercontrol element containing many canvas layers. It's a vector image imported with Blend. I created a .GIF model for the initial frame, and set a frame rate for each layer (40ms). In creating a .gif its to easy to control a frame speed for each layer. I'm now trying to make that motion in WPF using Storyboard, and to control appearance for each layer I'm using Visibility state like in my source code :
<UserControl.Resources>
<Storyboard x:Key="ProgressAnimation" RepeatBehavior="Forever">
<ObjectAnimationUsingKeyFrames BeginTime="00:00:00.0000000" Storyboard.TargetName="Layer1" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="00:00:00.2000000" Value="{x:Static Visibility.Visible}"/>
<DiscreteObjectKeyFrame KeyTime="00:00:00.4500000" Value="{x:Static Visibility.Collapsed}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames BeginTime="00:00:00.1000000" Storyboard.TargetName="Layer2" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="00:00:00.2000000" Value="{x:Static Visibility.Visible}"/>
<DiscreteObjectKeyFrame KeyTime="00:00:00.4500000" Value="{x:Static Visibility.Collapsed}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames BeginTime="00:00:00.2290000" Storyboard.TargetName="Layer3" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="00:00:00.2000000" Value="{x:Static Visibility.Visible}"/>
<DiscreteObjectKeyFrame KeyTime="00:00:00.4500000" Value="{x:Static Visibility.Collapsed}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</UserControl.Resources>
And of course I set a trigger :
<UserControl.Triggers>
<EventTrigger RoutedEvent="FrameworkElement.Loaded">
<BeginStoryboard x:Name="ProgressAnimationBeginStoryboard" Storyboard="{StaticResource ProgressAnimation}"/>
</EventTrigger>
</UserControl.Triggers>
Now the code works perfectly, but I truing do increase speed of the element, and got in trouble with that. Wen I set SpeedRation for my StoryBoard the element flashing/blinking and works very unstable.
Please help me to understand and learn a better method to do it right.

Related

WPF storyboard animation repeats

I have a trigger that fires off an OptionsShow storyboard animation when a button is clicked. This works with no problem. When I click an options button that I created, I made a grid fade in over it, similar to a custom tooltip. When the user leaves that grid, I make it fade out with the OptionsHide storyboard animation. If I leave the grid and quickly hover over the grid before it completely goes away, the grid constantly flashes.
It seems that the constant flashing occurs because the initial hide animation cannot complete, but I can't seem to figure out how to debug this. I don't have an "OnEnter" grid trigger to reshow the grid, so I'm not really sure when it shows the grid with opacity 100%, begins to fade and the constantly repeats this process.
If anyone has any experience with this, any help or info would be great.
<Window.Resources>
<Storyboard x:Key="OptionsShow">
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="Border">
<DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Visible}"/>
</ObjectAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="Border">
<EasingDoubleKeyFrame KeyTime="0" Value="0"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.2" Value="1"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
<Storyboard x:Key="OptionsHide">
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="Border">
<DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Visible}"/>
<DiscreteObjectKeyFrame KeyTime="0:0:0.2" Value="{x:Static Visibility.Collapsed}"/>
</ObjectAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="Border">
<EasingDoubleKeyFrame KeyTime="0" Value="1"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.2" Value="0"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</Window.Resources>
<Window.Triggers>
<!--This is my button in my menu bar. On click I show my tooltip grid.-->
<EventTrigger RoutedEvent="ButtonBase.Click" SourceName="button">
<BeginStoryboard Storyboard="{StaticResource OptionsShow}"/>
</EventTrigger>
<!--When I leave the tooltip grid, make the tooltip grid fade out.-->
<EventTrigger RoutedEvent="UIElement.MouseLeave" SourceName="Border">
<BeginStoryboard x:Name="OptionsHide_BeginStoryboard" Storyboard="{StaticResource OptionsHide}"/>
</EventTrigger>
</Window.Triggers>

wpf use VisualStateManager to change Visibility

I'm working on transitioning some code from silverlight to WPF, and my VisualStates are not working correctly.
I am using visualstatemanager to control the visibility of some text fields. I am not using any transitions to animate the change, I just want the fields to be collapsed in one state, then visible in another.
Xaml from silverlight:
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="LostPasswordStates">
<VisualState x:Name="LostPassword_Start">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="lbl_UserName" Storyboard.TargetProperty="(UIElement.Visibility)">
<DiscreteObjectKeyFrame KeyTime="00:00:00" Value="Visible" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="txt_UserName" Storyboard.TargetProperty="(UIElement.Visibility)">
<DiscreteObjectKeyFrame KeyTime="00:00:00" Value="Visible" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="txt_UserName" Storyboard.TargetProperty="(TextBox.IsReadOnly)">
<DiscreteObjectKeyFrame KeyTime="00:00:00" Value="False" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="LostPassword_Success">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="lbl_UserName" Storyboard.TargetProperty="(UIElement.Visibility)">
<DiscreteObjectKeyFrame KeyTime="00:00:00" Value="Collapsed" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="txt_UserName" Storyboard.TargetProperty="(UIElement.Visibility)">
<DiscreteObjectKeyFrame KeyTime="00:00:00" Value="Collapsed" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="btn_Reset" Storyboard.TargetProperty="(UIElement.Visibility)">
<DiscreteObjectKeyFrame KeyTime="00:00:00" Value="Collapsed" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
I get the following exception :
An unhandled exception of type 'System.Windows.Media.Animation.AnimationException' occurred in PresentationCore.dll
Additional information: Cannot animate the 'Visibility' property on a 'System.Windows.Controls.TextBox' using a 'System.Windows.Media.Animation.ObjectAnimationUsingKeyFrames'. For details see the inner exception.
So my question to you is:
If I can't use a System.Windows.Media.Animation.ObjectAnimationUsingKeyFrames for this, what should I be using?
This works for me, using .NET 4.5:
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="LostPasswordStates">
<VisualState x:Name="LostPassword_Start">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="lbl_UserName" Storyboard.TargetProperty="(UIElement.Visibility)">
<DiscreteObjectKeyFrame KeyTime="00:00:00" Value="{x:Static Visibility.Visible}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="txt_UserName" Storyboard.TargetProperty="(UIElement.Visibility)">
<DiscreteObjectKeyFrame KeyTime="00:00:00" Value="{x:Static Visibility.Visible}" />
</ObjectAnimationUsingKeyFrames>
<BooleanAnimationUsingKeyFrames Storyboard.TargetName="txt_UserName" Storyboard.TargetProperty="(TextBox.IsReadOnly)">
<DiscreteBooleanKeyFrame KeyTime="00:00:00" Value="False" />
</BooleanAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="LostPassword_Success">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="lbl_UserName" Storyboard.TargetProperty="(UIElement.Visibility)">
<DiscreteObjectKeyFrame KeyTime="00:00:00" Value="{x:Static Visibility.Collapsed}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="txt_UserName" Storyboard.TargetProperty="(UIElement.Visibility)">
<DiscreteObjectKeyFrame KeyTime="00:00:00" Value="{x:Static Visibility.Collapsed}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="btn_Reset" Storyboard.TargetProperty="(UIElement.Visibility)">
<DiscreteObjectKeyFrame KeyTime="00:00:00" Value="{x:Static Visibility.Collapsed}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
There are two changes to your current code:
Instead of "Collapsed" and "Visible", the Value is set to "{x:Static Visibility.Collapsed}" and "{x:Static Visibility.Visible}";
The IsReadOnly property uses a BooleanAnimationUsingKeyFrames instead of an ObjectAnimationUsingKeyFrames;
You can only animate properties of numeric types (double). Visibility can not be animated because it is enum an there is no way to animate this meaningfull.
If you want to fadeout something you can use the opacity property.

Setting the Visibility of an Element to Collapsed when Storyboard completes using XAML

I have a storyboard animation that fades a control out of view using the Opacity property. When it completes, I want to set the Visibility of the control to Collapsed.
I'd like to be able to do the reverse as well... Set the Visibility to Visible and then use a storyboard to fade the control into view.
I know I can hook up events, but I would like to do this all in XAML. Is it possible?
you can do this in the animation as well
<Window.Resources>
<Storyboard x:Key="OnLoaded1">
<ObjectAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="button" Storyboard.TargetProperty="(UIElement.Visibility)">
<DiscreteObjectKeyFrame KeyTime="00:00:00" Value="{x:Static Visibility.Visible}"/>
<DiscreteObjectKeyFrame KeyTime="00:00:00.8000000" Value="{x:Static Visibility.Collapsed}"/>
<DiscreteObjectKeyFrame KeyTime="00:00:01.4000000" Value="{x:Static Visibility.Visible}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</Window.Resources>
<Window.Triggers>
<EventTrigger RoutedEvent="FrameworkElement.Loaded">
<BeginStoryboard Storyboard="{StaticResource OnLoaded1}"/>
</EventTrigger>
</Window.Triggers>

Change the background image of a Button when pressed using VisualStateManager

I have this button :
<Button x:Name="PrevAdIcon" Tag="-1" Visibility="Collapsed" Width="80" Height="80" Click="PrevAd">
<Button.Background>
<ImageBrush AlignmentY="Top" Stretch="None" ImageSource="/Images/prev.png"></ImageBrush>
</Button.Background>
</Button>
How can I change the background to /Images/prev-selected.png when a user pressed the button ? It'll give him a feedback, since it's a WP7 app
what I have so far (not working) :
<vsm:VisualState x:Name="Pressed">
<Storyboard>
<ObjectAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="Background" Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<ImageBrush ImageSource="/Images/prev-selected.png" Stretch="Fill"/>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</vsm:VisualState>
As far as I know, you can't change the value of the Source property on the Image element by using the VisualStateManager. However, you can just add two Image elements to the ControlTemplate: one for the Normal state and one for the Pressed state, and toggle the Visibility in the Pressed state.
<VisualState x:Name="Pressed">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="Img">
<DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="PressedImg">
<DiscreteObjectKeyFrame KeyTime="0" Value="Visible" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
See Peter Torr's post on "Why can't I change the Background of my Button on a Click event?" for an example and explanation of how to do this.
To add more information to Derek's answer, you should look at Gambit's answer here for full XAML that works

WPF TextBlock text changed notify

I have a screen contain about 15-20 TextBlocks each one bind to a different property, at first all the TextBlocks are empty the text update come from other client.
The thing I want to do is to animate flashing text for 3 seconds when ever text change.
I used the below storyboard to make that happen:
<Setter Property="Visibility" Value="Visible"/>
<Style.Triggers>
<EventTrigger RoutedEvent="UIElement.MouseEnter">
<BeginStoryboard >
<Storyboard Duration="0:0:03">
<ObjectAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetProperty="(UIElement.Visibility)">
<DiscreteObjectKeyFrame KeyTime="00:00:00" Value="{x:Static Visibility.Visible}"/>
<DiscreteObjectKeyFrame KeyTime="00:00:00.5" Value="{x:Static Visibility.Hidden}"/>
<DiscreteObjectKeyFrame KeyTime="00:00:01" Value="{x:Static Visibility.Visible}"/>
<DiscreteObjectKeyFrame KeyTime="00:00:01.5" Value="{x:Static Visibility.Hidden}"/>
<DiscreteObjectKeyFrame KeyTime="00:00:02" Value="{x:Static Visibility.Visible}"/>
<DiscreteObjectKeyFrame KeyTime="00:00:02.5" Value="{x:Static Visibility.Hidden}"/>
<DiscreteObjectKeyFrame KeyTime="00:00:03" Value="{x:Static Visibility.Visible}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Style.Triggers>
</Style>
Using the mouse enter event the text flash is fine but using the Binding.TargetUpdated event didn't trigger anything.
Anyone know about event that raise when the TextBlock text is changed ?
did you set the NotifyOnTargetUpdated property to true
<TextBlock Text="{Binding Path=YourProperty, NotifyOnTargetUpdated=True}" TargetUpdated="OnTargetUpdated"/>
Already a bit old, but here the solution in pure xaml:
<TextBlock VerticalAlignment="Center"
Text="{Binding ErrorMsg, NotifyOnTargetUpdated=True}">
<TextBlock.Triggers>
<EventTrigger RoutedEvent="Binding.TargetUpdated">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation BeginTime="0:0:0"
Duration="0:0:1"
From="0.0"
Storyboard.TargetProperty="Opacity"
To="1.0" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</TextBlock.Triggers>
</TextBlock>

Resources