Trouble animating an image, Seems Storyboard doesn't start - wpf

My Code is posted Below. I am creating an image, and attempting to add animation to it. I am sure it was working at one point, I made a small change, it failed I undid the change (literally undo) and now it continues to fail. I am attempting to make an image change ever half second to another image, then change back after another half second.
<Image Height="30" HorizontalAlignment="Left" Margin="198,90,0,0" Name="OldMan" Stretch="Fill" VerticalAlignment="Top" Width="30" Source="/TestingWpF;component/Images/Old1.png" >
<Image.Triggers>
<EventTrigger RoutedEvent="Window.Loaded">
<BeginStoryboard>
<Storyboard >
<ObjectAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="OldMan" Storyboard.TargetProperty="(Image.Source)" RepeatBehavior="Forever">
<DiscreteObjectKeyFrame KeyTime="00:00:00.5000000">
<DiscreteObjectKeyFrame.Value>
<BitmapImage UriSource="/TestingWpF;component/Images/Old1.png" />
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
<DiscreteObjectKeyFrame KeyTime="00:00:01.0000000">
<DiscreteObjectKeyFrame.Value>
<BitmapImage UriSource="/TestingWpF;component/Images/Old2.png" />
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Image.Triggers>
</Image>

The problem is that you don't have your duration set. You'll just get the first keyframe, but not the next. Try adding something like Duration="00:00:01.5" to ObjectAnimationUsingKeyFrames

Related

How to animate a TemplatedParent property inside a storyboard inside a controltemplate

<VisualState x:Name="MouseOver">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="Bd"
Storyboard.TargetProperty="Fill">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource
ButtonHoverBackgroundBrush}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="Bd"
Storyboard.TargetProperty="Stroke">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource
ButtonHoverBorderBrush}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Duration="0"
Storyboard.TargetProperty="Foreground"
Storyboard.TargetName="ContentControl">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource
LightForegroundBrush}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
Instead of going Storyboard.TargetName=ContentControl and Storyboard.TargetProperty=Foreground,
i would like to Animate the templated parent's foreground, and the content control to just have it's foreground property binded to the templated parent
Foreground={TemplateBinding Foreground}
The reason for this is that when i use the control with this template, i want to be able to do :
<Button Width="125"
Height="30"
Click="OnButtonClick"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Margin="50,54,0,0">
<Button.Content>
<controls:SomeCustomControl '
Foreground="{Binding Path=Foreground,
RelativeSource={RelativeSource AncestorType=
{x:Type Button}}}" />
</Button.Content>
</Button>
I tried doing :
<ObjectAnimationUsingKeyFrames Duration="0" Storyboard.Target="{Binding Path=Foreground, RelativeSource={RelativeSource TemplatedParent}}">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource LightForegroundBrush}" />
</ObjectAnimationUsingKeyFrames>
however this crashes.
Any suggestions on how this can be done? Thanks in advance.
Same Problem on my Side ....
But it could be that we just thought in the wrong way.
It is "Content" to be styled but no one knows what Content it would be. So the "right" way would be to say that its the work for the Control you put into the Content.
Example, if you put a Button into a ContentControl, the Button style handle the VSM not the ContentControl around it.
That ist not the exactly answer to your question but maybe some help to understand why this isnĀ“t some option.
Edit:
After some research i found this:
Animating a TextBox.Foreground in WPF
It feels not the best practice but it could be work for your problem.

WPF routedevent storyboard begin only if height is zero

I have the following XAML for a border trigger that uses a routed event
<Border.Triggers>
<EventTrigger RoutedEvent="MouseLeftButtonUp" EnterActions="">
<BeginStoryboard>
<Storyboard>
<ObjectAnimationUsingKeyFrames BeginTime="0" Duration="0:0:0.4" Storyboard.Target="{Binding ElementName=messageWriterDefinition}" Storyboard.TargetProperty="Height">
<DiscreteObjectKeyFrame >
<DiscreteObjectKeyFrame.Value>
<GridLength>20</GridLength>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
...
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Border.Triggers>
This trigger fires when the border and containing elements are clicked and animates cause the target to animate open from height of Zero to 200
The trigger works really well but each time the border receives the event the animation runs and the target animates open again (even if already open)
How can one add a condition to the trigger that effectively ignores the animation is the target already has a height greater than Zero?
You may use a DoubleAnimation instead of an ObjectAnimationUsingKeyFrames. By only setting its To property, but not From, the animation starts from the current property value. It requires that you also set an initial value of the Height of the Border:
<Border Height="20" ...>
<Border.Triggers>
<EventTrigger RoutedEvent="MouseLeftButtonUp">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Height"
To="200" Duration="0:0:0.4"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Border.Triggers>
</Border>

How to reuse interactions and interactivity attached to a grid

I am trying to make use of interactivity and interactions libraries in wpf app. I need it to work on a grid, and it works well, but now I need this stuff in multiple grids and I cant find a way of reusing it. Here is the xaml
<Grid>
<i:Interaction.Behaviors>
<ei:DataStateBehavior Binding="{Binding KeepAlive}"
FalseState="InactiveState"
TrueState="ActiveState"
Value="false" />
</i:Interaction.Behaviors>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState x:Name="ActiveState" />
<VisualState x:Name="InactiveState">
<Storyboard>
<ObjectAnimationUsingKeyFrames
Storyboard.TargetName="ActiveContainer"
Storyboard.TargetProperty="(Control.IsEnabled)">
<DiscreteObjectKeyFrame KeyTime="0:0:0">
<DiscreteObjectKeyFrame.Value>
<system:Boolean>False</system:Boolean>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames
Storyboard.TargetName="InactiveContainer"
Storyboard.TargetProperty="(UIElement.Visibility)">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<Visibility>Visible</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Border>
<Grid>
Content comes here, Texboxes, labels when active or inactive etc.
</Grid>
</Border>
</Grid>
It works great, but how can I refactor the above code so I can reuse the exact same behaviour on multiple grids?
Thank you
A few approach immediately come up: style or resource. But Blend behavior cannot work when declared in resources. You can use attached property. See:
How to add a Blend Behavior in a Style Setter
I created generic behaviour, from which you could simply inherit and add to your style
see my answer below
https://stackoverflow.com/a/31292989/4711853

WPF - animate image source change

I'm pretty new to WPF but I think what I need to do is relatively simple. I need to create an image "animation", where I am changing an image source every .25 of a second.
I have a folder named "animation" with images 1 to 25 png live (named 1.png, 2.png... 25.png). Each image correlate to different frame of my animation.
I want to write xaml to change the image from 1 to 2, from 2 to 3, for 3 to 4 etc every .25 seconds until it gets to the 25th image, then it should loop back to the start.
I most likely will need to write some c# to do this. I want it to run on a thread that can interact with the UI (as in update the image) but not block the UI thread.
Thanks in advance!
A pure XAML solution could look like this, of course with different images and timings.
<Image>
<Image.Triggers>
<EventTrigger RoutedEvent="Loaded">
<BeginStoryboard>
<Storyboard RepeatBehavior="Forever">
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Source"
Duration="0:0:2">
<DiscreteObjectKeyFrame KeyTime="0:0:0">
<DiscreteObjectKeyFrame.Value>
<BitmapImage UriSource="C:\Users\Public\Pictures\Sample Pictures\Koala.jpg"/>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
<DiscreteObjectKeyFrame KeyTime="0:0:1">
<DiscreteObjectKeyFrame.Value>
<BitmapImage UriSource="C:\Users\Public\Pictures\Sample Pictures\Penguins.jpg"/>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Image.Triggers>
</Image>

Animating height in WIndows Phone

I have a grid containing two elements, a search form and a custom UC to show items. When my page loads, the viewer control is hidden. I ant to animate it in with a storyboard when a button on the search form is clicked. I'm stuck at the To=... part of the animation. I want to animate it to the height of the parent container and have it slid up from the bottom. Is this possible?
For reference, this is my tree structure:
Page resources:
<Storyboard x:Name="animateViewSlide" Storyboard.TargetName="SearchForm" >
<DoubleAnimation Storyboard.TargetProperty="Height" To="???" Duration="100"/>
</Storyboard>
Control body:
<Grid x:Name="LayoutRoot">
<Grid x:Name="SearchForm" Margin="6,6,6,70">
<uc:AwesomeViewer x:Name="awesomeView" Awesomeness="{Binding SelectedAwesomeThing}" Visibility="Collapsed"/>
</Grid>
UPDATE
I did figure out a bit better way of doing this, instead of using the Margin to step through the animation, just animate the Y axis with a TranslateTransform like;
<Grid x:Name="ItemToMove"
Visibility="{Binding Condition, Converter={StaticResource boolVisConv}}" VerticalAlignment="Bottom" HorizontalAlignment="Center" Margin="30,0,0,-32" Opacity="0">
<Grid.RenderTransform>
<TranslateTransform x:Name="notified" Y="40" />
</Grid.RenderTransform>
<Grid.Triggers>
<EventTrigger RoutedEvent="Grid.Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="notified" Storyboard.TargetProperty="Y">
<SplineDoubleKeyFrame KeyTime="0:0:1.25" Value="0" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="ItemToMove" Storyboard.TargetProperty="Opacity">
<SplineDoubleKeyFrame KeyTime="0:0:1.55" Value="1" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Grid.Triggers>
END UPDATE
Your trouble is going to stem from trying to animate an automatically calculated value (Height) so I would scrap that idea unless you want to use hard coded size values on your Parents/Children or just assume for example that if the app is restricted to Portrait Mode only....then your "To" value is 800px, except I imagine that's not what you're looking for.
Now then, you would usually hope you could just feed the rendered size into your "To" value, like maybe via To="{Binding ActualHeight, ElementName=LayoutRootOROTHERParentContainer}" right? Yet nay, that won't work either...
So while someone else may have a better way, the only way I've found is to instead leave the Auto calculated sizes alone to do their thing, and instead animate a stepping of the object Margin via ObjectAnimationUsingKeyFrames which when paired with an Opacity transition via DoubleAnimationUsingKeyFrames actually looks quite nice, except it will add a bunch of additional XAML for the process. So as a concept you might try something more like this (however if you come across a better solution, I'd sure like to know it also. As a designer for a living, I run into this relatively often.)
Concept Example;
(The Storyboard)
<Storyboard x:Name="Kaboom">
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(FrameworkElement.Margin)" Storyboard.TargetName="border">
<DiscreteObjectKeyFrame KeyTime="0:0:0.1">
<DiscreteObjectKeyFrame.Value>
<Thickness>0,750,0,0</Thickness>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
<DiscreteObjectKeyFrame KeyTime="0:0:0.2">
<DiscreteObjectKeyFrame.Value>
<Thickness>0,600,0,0</Thickness>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
<DiscreteObjectKeyFrame KeyTime="0:0:0.3">
<DiscreteObjectKeyFrame.Value>
<Thickness>0,550,0,0</Thickness>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
<DiscreteObjectKeyFrame KeyTime="0:0:0.4">
<DiscreteObjectKeyFrame.Value>
<Thickness>0,500,0,0</Thickness>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
<DiscreteObjectKeyFrame KeyTime="0:0:0.5">
<DiscreteObjectKeyFrame.Value>
<Thickness>0,450,0,0</Thickness>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
<DiscreteObjectKeyFrame KeyTime="0:0:0.6">
<DiscreteObjectKeyFrame.Value>
<Thickness>0,400,0,0</Thickness>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
<DiscreteObjectKeyFrame KeyTime="0:0:0.7">
<DiscreteObjectKeyFrame.Value>
<Thickness>0,350,0,0</Thickness>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
<DiscreteObjectKeyFrame KeyTime="0:0:0.8">
<DiscreteObjectKeyFrame.Value>
<Thickness>0,300,0,0</Thickness>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
<DiscreteObjectKeyFrame KeyTime="0:0:0.9">
<DiscreteObjectKeyFrame.Value>
<Thickness>0,250,0,0</Thickness>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
<DiscreteObjectKeyFrame KeyTime="0:0:1">
<DiscreteObjectKeyFrame.Value>
<Thickness>0,200,0,0</Thickness>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
<DiscreteObjectKeyFrame KeyTime="0:0:1.1">
<DiscreteObjectKeyFrame.Value>
<Thickness>0,150,0,0</Thickness>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
<DiscreteObjectKeyFrame KeyTime="0:0:1.2">
<DiscreteObjectKeyFrame.Value>
<Thickness>0,100,0,0</Thickness>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
<DiscreteObjectKeyFrame KeyTime="0:0:1.3">
<DiscreteObjectKeyFrame.Value>
<Thickness>0,50,0,0</Thickness>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
<DiscreteObjectKeyFrame KeyTime="0:0:1.4">
<DiscreteObjectKeyFrame.Value>
<Thickness>0</Thickness>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="border">
<EasingDoubleKeyFrame KeyTime="0:0:0.6" Value="0.01"/>
<EasingDoubleKeyFrame KeyTime="0:0:1.6" Value="1"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
A quick adhoc example of the concept in action;
<Grid Height="800" Width="480" x:Name="ParentContainer">
<!-- Your SearchForm thingy with its funky margins already set like your example -->
<Rectangle Margin="6,6,6,70" Fill="Green" />
<Button Height="100" Width="100" Content="Click Me!" HorizontalAlignment="Left" VerticalAlignment="Top">
<!-- Quick button to show it in action -->
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<ei:ControlStoryboardAction Storyboard="{StaticResource Kaboom}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
<!-- Your Awesomeness -->
<Border x:Name="border" Width="300" Background="Blue" HorizontalAlignment="Right" Margin="0,800,0,0" Opacity="0">
<TextBlock x:Name="textBlock" Text="OH
SNAP!!!
Say
WHAAA??"
TextAlignment="Center" VerticalAlignment="Center"
FontSize="40" FontWeight="Bold" Foreground="White"/>
</Border>
</Grid>
Anyway, probably not exactly what you're hoping for, but is an effective alternative especially with a little tweaking unless like I said, you want to hardcode your object sizes so you have something viable to set your "To" value to...which, in the case of a phone that's restricted to the standard 800x480 Portrait Mode Only you may very well want to. However if you don't have that option, I've pulled off some pretty nifty designs using this method instead.
Hope this helps and best of luck!

Resources