Storyboard for multiple frames - c#

I would like to animate the opacity of three frames and the timeline for their opacity value should look like in the image. Also the animation should be forever but I also want a delay between each cycle. I mean the opacity should hold onto the last value of '1' for some specified time and then the timeline should repeat again. I tried using a storyboard with three double animations but I cannot figure out the delay between each cycle and the delay between each animation. Setting begin time for each animation did not work for me.

With the flexibility of Animation in WPF, there are many ways to solve this. Here I introduce the most intuitive solution. From your image, you have to use some kind of discrete KeyFrame. In this case we need 3 DoubleAnimationUsingKeyFrames, each one should have 2 DiscreteDoubleKeyFrame. All these keyframes should be the same. We just need to set the BeginTime of DoubleAnimationUsingKeyFrames appropriately. We don't need to set the Duration, it will be deferred automatically based on the KeyTime (of DiscreteDoubleKeyFrame) combined with the BeginTime (of DoubleAnimationUsingKeyFrames).
However we have to set the Duration for the last DoubleAnimationUsingKeyFrames if you want some delay between the cycles.
Here is a simple example:
<StackPanel>
<StackPanel.Triggers>
<EventTrigger RoutedEvent="Loaded">
<BeginStoryboard>
<Storyboard Storyboard.TargetProperty="Opacity"
RepeatBehavior="Forever">
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="i1"
BeginTime="0:0:0">
<DiscreteDoubleKeyFrame KeyTime="0:0:0" Value="0"/>
<DiscreteDoubleKeyFrame KeyTime="0:0:1" Value="1"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="i2"
BeginTime="0:0:1">
<DiscreteDoubleKeyFrame KeyTime="0:0:0" Value="0"/>
<DiscreteDoubleKeyFrame KeyTime="0:0:1" Value="1"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="i3"
BeginTime="0:0:2" Duration="0:0:3">
<DiscreteDoubleKeyFrame KeyTime="0:0:0" Value="0"/>
<DiscreteDoubleKeyFrame KeyTime="0:0:1" Value="1"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</StackPanel.Triggers>
<TextBlock Name="i1">Item 1</TextBlock>
<TextBlock Name="i2">Item 2</TextBlock>
<TextBlock Name="i3">Item 3</TextBlock>
</StackPanel>
I used TextBlock in this code for simplicity. Here you can see that the time of being in 0 opacity (for each TextBlock) is 1 second. From that you can derive the BeginTime correctly for each DoubleAnimationUsingKeyFrames. The last one has Duration of 3 seconds, that means the delay is about 2 seconds (1 second of the last animation is deducted from the total 3).

Related

Animation bound KeyTime not working

I'm currently trying to make a TextBlock fade in and out when it's Text property changes. I have this XAML:
<TextBlock DataContext="{Binding ElementName=main, Path=DataContext}"
Height="18"
Text="{Binding CurrentStatus, NotifyOnTargetUpdated=True}">
<TextBlock.Triggers>
<EventTrigger RoutedEvent="Binding.TargetUpdated">
<BeginStoryboard>
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="Opacity">
<EasingDoubleKeyFrame KeyTime="0" Value="0"/>
<EasingDoubleKeyFrame KeyTime="0:0:0:1" Value="1"/>
<EasingDoubleKeyFrame KeyTime="{Binding AnimationTime}" Value="1"/>
<EasingDoubleKeyFrame KeyTime="0:0:0:1" Value="0"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</TextBlock.Triggers>
</TextBlock>
What I would except from this is: First, take 1 second to fade in, then stay at Opacity 1 for the duration of AnimationTime and then take 1 second to fade out. I have checked the value of AnimationTime with Snoop, and the value is fine. But the animation seems to ignore the bound value and the fade out also doesnt work. So now, it fades in like expected but then is instantly gone. The Text is also still there. Does anyone see anything wrong with that code?
EDIT: AnimationTime is a TimeSpan btw

C# - Windows Phone 8, how can I start animation or storyboard first before I changed the visibility of an Element

I have a question, how can I make an animation running first before the visibility changed on an XAML element?
The situation should be like this.
<Grid Name=Header Visiblity="visible">
<Grid.Resources>
<Storyboard x:Name="HeaderGridUp">
<DoubleAnimationUsingKeyFrames
Storyboard.TargetProperty="Height"
Storyboard.TargetName="HeaderGrid">
<EasingDoubleKeyFrame Value="30" KeyTime="00:00:02">
<EasingDoubleKeyFrame.EasingFunction>
<ExponentialEase EasingMode="EaseOut"/>
</EasingDoubleKeyFrame.EasingFunction>
</EasingDoubleKeyFrame>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
<Storyboard x:Name="HeaderGridDown">
<DoubleAnimationUsingKeyFrames
Storyboard.TargetProperty="Height"
Storyboard.TargetName="HeaderGrid">
<EasingDoubleKeyFrame Value="30" KeyTime="00:00:02">
<EasingDoubleKeyFrame.EasingFunction>
<ExponentialEase EasingMode="EaseIn"/>
</EasingDoubleKeyFrame.EasingFunction>
</EasingDoubleKeyFrame>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</Grid.Resources>
</Grid>
<Grid Name=Items Visiblity="collapsed">
<Grid.Resources>
<Storyboard x:Name="ItemsGridUp">
<DoubleAnimationUsingKeyFrames
Storyboard.TargetProperty="Height"
Storyboard.TargetName="ItemsGrid">
<EasingDoubleKeyFrame Value="30" KeyTime="00:00:02">
<EasingDoubleKeyFrame.EasingFunction>
<ExponentialEase EasingMode="EaseOut"/>
</EasingDoubleKeyFrame.EasingFunction>
</EasingDoubleKeyFrame>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
<Storyboard x:Name="ItemsGridDown">
<DoubleAnimationUsingKeyFrames
Storyboard.TargetProperty="Height"
Storyboard.TargetName="ItemsGrid">
<EasingDoubleKeyFrame Value="30" KeyTime="00:00:02">
<EasingDoubleKeyFrame.EasingFunction>
<ExponentialEase EasingMode="EaseIn"/>
</EasingDoubleKeyFrame.EasingFunction>
</EasingDoubleKeyFrame>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</Grid.Resources>
</Grid>
In my case, I would like an animation that move like Fade in and Fade out, that's why I make two storyboard each grid. First thing that I want my app run is.
The current state of HeaderGrid is visible, and when I touch a button, this grid will be going up and the visibility changed to collapsed. After that, the ItemsGrid will be going up change it's visibility and then going up replacing the HeaderGrid original place. Then I do the revert of the exact thing.
Can I possible doing that? and I would like to do it in code behind.
Any answer will be appreciated. :)
Thank You.
Regards,
Budi Prasetyo
where you were supposed to add the visibility code in c#, u start a dispatchertimer with interval equal to your animations length and when the timer ticks change the visibility
DispatcherTimer timer = new DispatcherTimer();
timer.Interval = new TimeSpan(0,0,x); //length of your animation in seconds
in main()
{
timer.Tick += timer_Tick;
}
and the event handler for the tick
void timer_Tick(object sender, EventArgs e)
{
timer.Stop();
element.Visibility = Visibility.Visible; //or Collapsed
}
and where you're supposed to change the visibility of the element, just start the timer
timer.Start();
hope it helps :) and not too late ;)
Once you set the Visibility of any element to Collapsed, you will not be able to see any animation, because the element is already collapsed. I just had this issue myself, wanting to ease out when items disappear from a list. My solution was to add another property to my ViewModel, IsRemoving, then set this to true before removing the element. You can then bind the animation to the changing of IsRemoving property to run the animation before setting Visibility on the element.
You can do the trick like this, using some async/await magic. This will delay for 1 second before actually removing the item. Because the delay is awaited, UI will not hang.
public async void RemoveItem(SomeItem item){
IsRemoving = true;
await Task.Delay(1000);
<Your collection>.Remove(item);
IsRemoving = false;
}
EDIT: IN XAML:
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding IsRemoving}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(FrameworkElement.LayoutTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)" Storyboard.TargetName="border">
<EasingDoubleKeyFrame KeyTime="0" Value="1">
<EasingDoubleKeyFrame.EasingFunction>
<QuinticEase EasingMode="EaseOut"></QuinticEase>
</EasingDoubleKeyFrame.EasingFunction>
</EasingDoubleKeyFrame>
<EasingDoubleKeyFrame KeyTime="0:0:0.2" Value="0">
<EasingDoubleKeyFrame.EasingFunction>
<QuinticEase EasingMode="EaseOut"></QuinticEase>
</EasingDoubleKeyFrame.EasingFunction>
</EasingDoubleKeyFrame>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
Hope it helps :-)

How to Get C# with WPF/XAML Animation Running Smoothly with Other Code Running Concurrently

I have looked in Stackoverflow and have not seen anything with regard to this yet.
Currently, I am using an animation to get a groupbox to flash while an operation is occurring (i.e. other work). Unfortunately, the flashing is not smooth due to the other operations/work being run. I have tried by interspersing ThreadHelper.DoEvents() which helps but is not nearly enough. Is there a way to cause the animation updating to occur smoothly (i.e. flashing is not consistent) without putting all the other operations on their own thread (believed to be too complex due to interaction with UI)? Preferred would be to put the updating of the groupbox animation in its own thread (or something like this or ??)?
The animation is as follows:
<Storyboard x:Key="FlashingGroupBoxForTest" RepeatBehavior="Forever">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="StartTest">
<EasingDoubleKeyFrame KeyTime="0" Value="1"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="0"/>
<EasingDoubleKeyFrame KeyTime="0:0:1" Value="1"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
Triggers are used to start and stop the animation
<ei:DataTrigger Binding="{Binding PerformingFocusTest, Mode=OneWay}" Value="True">
<ei:ControlStoryboardAction Storyboard="{StaticResource FlashingGroupBoxForTest}"
ControlStoryboardOption="Play"/>
</ei:DataTrigger>
<ei:DataTrigger Binding="{Binding PerformingFocusTest, Mode=OneWay}" Value="False">
<ei:ControlStoryboardAction Storyboard="{StaticResource FlashingGroupBoxForTest}"
ControlStoryboardOption="Stop"/>
</ei:DataTrigger>
Thanks for looking and any help is appreciated.
Best,
Buck

Laggy animation on Windows Phone

Hi I have got a performance problem that I am unable to solve. Using Blend, I have created an animation showing and hiding a grid. It is invoked when the toggle switch button is checked, and it works. The problem is, that it works really laggy and invokes after a few seconds of delay. I test the application on Nokia Lumia 920. Could you please help me find out what is wrong?
Here is the code of animation, that has been created using blend:
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="Collapsing">
<VisualStateGroup.Transitions>
<VisualTransition GeneratedDuration="0:0:0.5" />
</VisualStateGroup.Transitions>
<VisualState x:Name="Hidden">
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(FrameworkElement.Height)"
Storyboard.TargetName="CollapsingGrid">
<EasingDoubleKeyFrame KeyTime="0"
Value="95" />
<EasingDoubleKeyFrame KeyTime="0:0:0.5"
Value="0">
<EasingDoubleKeyFrame.EasingFunction>
<CubicEase EasingMode="EaseOut" />
</EasingDoubleKeyFrame.EasingFunction>
</EasingDoubleKeyFrame>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(FrameworkElement.Height)"
Storyboard.TargetName="anonymousOnLabel">
<EasingDoubleKeyFrame KeyTime="0:0:0.5"
Value="0" />
<EasingDoubleKeyFrame KeyTime="0:0:1"
Value="91" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(FrameworkElement.Height)"
Storyboard.TargetName="SettingsSharePicTglBtn">
<EasingDoubleKeyFrame KeyTime="0"
Value="95" />
<EasingDoubleKeyFrame KeyTime="0:0:0.5"
Value="0" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Unhidden">
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(FrameworkElement.Height)"
Storyboard.TargetName="CollapsingGrid">
<EasingDoubleKeyFrame KeyTime="0:0:0.5"
Value="0" />
<EasingDoubleKeyFrame KeyTime="0:0:1"
Value="95">
<EasingDoubleKeyFrame.EasingFunction>
<CubicEase EasingMode="EaseOut" />
</EasingDoubleKeyFrame.EasingFunction>
</EasingDoubleKeyFrame>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(FrameworkElement.Height)"
Storyboard.TargetName="anonymousOnLabel">
<EasingDoubleKeyFrame KeyTime="0"
Value="91" />
<EasingDoubleKeyFrame KeyTime="0:0:0.5"
Value="0" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(FrameworkElement.Height)"
Storyboard.TargetName="SettingsSharePicTglBtn">
<EasingDoubleKeyFrame KeyTime="0"
Value="0" />
<EasingDoubleKeyFrame KeyTime="0:0:0.5"
Value="95" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
I invoke it the following way:
private void TglBtn_Tap(object sender, System.Windows.Input.GestureEventArgs e)
{
if ((bool)((ToggleSwitchButton)sender).IsChecked)
{
VisualStateManager.GoToState(this, "Unhidden", true);
}
else
{
VisualStateManager.GoToState(this, "Hidden", true);
}
}
I would recommend not animating the Width and Height properties. Each time these properties change, a full measure/arrange pass is performed on the visual tree, which is very expensive. Instead, you should try animating Scale on the grid's RenderTransform from 1.0 to 0.0.
Now, it's possible you're animating the height because you want things stacked under the grid to move up to fill the space taken up by the grid. In this case, you may need to perform some visual trickery, such as animating Translate on the things underneath the grid to move them up, then at the very end of the animation, as the last keyframe, you can reset the RenderTransforms and collapse the grid. Then, you will only suffer a single measure/arrange pass instead of one for each animation frame.
Finally, I would recommend reading up on Windows Phone performance considerations. This is a good document: http://bit.ly/15cExFz
And these two presentations are FANTASTIC. I can't recommend them enough. http://channel9.msdn.com/events/PDC/PDC10/CD03 & http://channel9.msdn.com/Events/Build/2012/3-048
I have had similar problem, but I have animated RotationX, RotationY properties of PlaneProjection using DoubleAnimation. The solution of problem have been found from this article. And it was adding of "magic" numbers ending in 0.1 – that tells the system it’s a ratio based on the width of the control, it's hack overload of a property but it gives real performance grow in some cases.
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(FrameworkElement.Height)" Storyboard.TargetName="anonymousOnLabel">
<EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="0.1" />
<EasingDoubleKeyFrame KeyTime="0:0:1" Value="91.1" />
</DoubleAnimationUsingKeyFrames>
And of course it not good idea to animate Width and Height properties directly because it will be Dependant Animation and will have performance impact.

Fade in/out a TextBlock in a Windows Store Application [XAML/C#]

can someone explain me how can I add a fade in and a fade out animation to a textblock when I load a form in a Windows Store application?
I tried the WPF method but it didn't work...
Thank you :)
Not sure if this is what you're looking for (or what "WPF method" didn't work), but with this resource:
<Page.Resources>
<Storyboard x:Name="Storyboard1">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="textBlock">
<EasingDoubleKeyFrame KeyTime="0" Value="0"/>
<EasingDoubleKeyFrame KeyTime="0:0:4" Value="1"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</Page.Resources>
invoked from OnNavigatedTo you'll get a fade-in effect (here on a specific instance called textBlock.) Obviously, you can adjust the duration and easing function to your liking - and perhaps generalize for use across various controls.
var f = this.Resources["Storyboard1"] as Storyboard;
if (f != null) f.Begin();

Categories