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
Related
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).
I have the following simple animation:
<Window x:Class="AnimationTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<StackPanel Background="Black">
<TextBox Name="Box" >
</TextBox>
<TextBlock Text="{Binding Text, ElementName=Box, NotifyOnTargetUpdated=True}" Foreground="White" >
<TextBlock.Style>
<Style TargetType="TextBlock" >
<Style.Triggers>
<EventTrigger RoutedEvent="Binding.TargetUpdated">
<BeginStoryboard>
<Storyboard>
<ColorAnimation AutoReverse="True" To="#A933FF" Duration="0:0:1" Storyboard.TargetProperty="Foreground.Color" FillBehavior="Stop" IsCumulative="True" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</StackPanel>
</Window>
It just makes flash a value when the value changes. if you write a letter you see it flash correctly to the color set in the animation and go back. But if you click several times the duration is longer (which is the desired behavior) but then it goes to the original color without fading out. Why does this happen and how to avoid it?
So once again, we have a question where a user provides some code and says why is this happening? The answer in this case is the normal answer to these questions:
You wrote some code to make it happen
So to dig a little deeper, you have asked:
if you write a letter you see it flash correctly to the color set in the animation and go back. But if you click several times the duration is longer (which is the desired behavior) but then it goes to the original color without fading out. Why does this happen and how to avoid it?
First, why does this happen?
So the reason why it is happening is because you declared a ColorAnimation that has no From value set, so it will always start from the current value, whether this value has been manipulated by an Animation or not:
<ColorAnimation AutoReverse="True" To="#A933FF" Duration="0:0:1" FillBehavior="Stop"
Storyboard.TargetProperty="Foreground.Color" IsCumulative="True" />
For a single character entered, you'll see the ColorAnimation as you expected. However, when you continually type further characters, it will already have reached your set purple colour and you won't see any further animations until you stop typing, because it is now trying to animate from your purple colour to the same purple colour.
Now, how to avoid it?
To fix this issue, either supply a From colour, or set the Duration to be much quicker, or preferably both:
<ColorAnimation AutoReverse="True" From="White" To="#A933FF" Duration="0:0:0.1"
Storyboard.TargetProperty="Foreground.Color" FillBehavior="Stop"
IsCumulative="True" />
You can achieve the desired result using ColorAnimationUsingKeyFrames this will offer you much precise control over the same using keyframes instead of reversing the double animation which loses the initial value after being invoked multiple time and FillBehavior stop force it to revert to original value as result of animation complere
sample for you
<TextBlock Text="{Binding Text, ElementName=Box, NotifyOnTargetUpdated=True}" Foreground="White" >
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
<EventTrigger RoutedEvent="Binding.TargetUpdated">
<BeginStoryboard>
<Storyboard>
<ColorAnimationUsingKeyFrames Duration="0:0:2" Storyboard.TargetProperty="Foreground.Color" >
<SplineColorKeyFrame Value="#A933FF"/>
<SplineColorKeyFrame Value="White" KeyTime="0:0:1"/>
</ColorAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
more cleaner approach involves stopping the previous storyboard and invoking a new one
<TextBlock Text="{Binding Text, ElementName=Box, NotifyOnTargetUpdated=True}" Foreground="White" >
<TextBlock.Style>
<Style TargetType="TextBlock" >
<Style.Resources>
<Storyboard x:Key="animate">
<ColorAnimationUsingKeyFrames Duration="0:0:2" Storyboard.TargetProperty="Background.Color" >
<SplineColorKeyFrame Value="#A933FF"/>
<SplineColorKeyFrame Value="White" KeyTime="0:0:1"/>
</ColorAnimationUsingKeyFrames>
</Storyboard>
</Style.Resources>
<Style.Triggers>
<EventTrigger RoutedEvent="Binding.TargetUpdated">
<StopStoryboard BeginStoryboardName="beginAnimate"/>
<BeginStoryboard x:Name="beginAnimate" Storyboard="{StaticResource animate}"/>
</EventTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
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 :-)
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.
I am building some WPF controls using .Net 4.0. One of these controls, called LoadingPane, is a custom control derived from ContentControl.
The only job of this LoadingPane control is to show a semi-transparent layer over it's contained content when it's IsLoading property is set to true.
I use some animations to do fade-in, fade-out when the IsLoading value changes.
When the overlay is shown an animation rotates a circle of elipses.
So far, so good. This all works very nicely. But here's my problem: when i set the Loading property to true the animation isn't shown directly. It takes about half a second. In this time the fade-in animation has already run, so the opacity effectively goes from 0 to 1 in one step.
Here's my animation code:
<ControlTemplate.Triggers>
<Trigger Property="IsLoading"
Value="True">
<Trigger.EnterActions>
<RemoveStoryboard BeginStoryboardName="EndAnimateLoadingCanvas" />
<BeginStoryboard Name="AnimateLoadingCanvas">
<Storyboard FillBehavior="Stop">
<ObjectAnimationUsingKeyFrames BeginTime="00:00:00"
Storyboard.TargetName="MyViewBoxje"
Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame Value="{x:Static Visibility.Visible}" />
</ObjectAnimationUsingKeyFrames>
<DoubleAnimation BeginTime="00:00:00"
Duration="00:00:00.5"
Storyboard.TargetName="MyViewBoxje"
Storyboard.TargetProperty="Opacity"
To="1" />
<DoubleAnimation BeginTime="00:00:00"
Duration="00:00:02"
Storyboard.TargetName="AnimatedRotateTransform"
Storyboard.TargetProperty="Angle"
From="360"
To="0"
RepeatBehavior="Forever" />
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<RemoveStoryboard BeginStoryboardName="AnimateLoadingCanvas" />
<BeginStoryboard Name="EndAnimateLoadingCanvas">
<Storyboard FillBehavior="Stop">
<DoubleAnimation BeginTime="00:00:00"
Duration="00:00:00.5"
Storyboard.TargetName="MyViewBoxje"
Storyboard.TargetProperty="Opacity"
To="0" />
<ObjectAnimationUsingKeyFrames BeginTime="00:00:00.5"
Storyboard.TargetName="MyViewBoxje"
Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame Value="{x:Static Visibility.Collapsed}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
</ControlTemplate.Triggers>
The strange thing is, when i use this control in a test window and i click the Loading checkbox repeatedly (and before the animation has finished) then the fade-in/fade-out animation does work as i expect it to work.
Can anyone help? Thanx in advance!
It's hard to see exactly what the problem is without seeing the rest of the code but my guess is that it has to do with the start values of the animated properties.
I implemented a custom control in WPF with a rectangle inside a viewbox and used the triggers + storyboards from the question to see the effect. Indeed, my first attempt did not fade in nor fade out.
What I did to solve it was by specifying From values in the animations so that they work regardless of what the original value of the DP's were:
<DoubleAnimation BeginTime="00:00:00"
Duration="00:00:00.5"
Storyboard.TargetName="MyViewBoxje"
Storyboard.TargetProperty="Opacity"
From="0"
To="1" />
Notice From="0" in the above animation. The end storyboard was modified the same way, to go from 1 to 0.
For completeness I set the opacity to 0 on the definition of the viewbox element inside the ControlTemplate as well.
Here is the complete source code for the relevant parts. The control is a standard WPF custom control inheriting from Control. It has a single dependency property called IsLoading (bool) which defaults to false:
public bool IsLoading
{
get { return (bool)GetValue(IsLoadingProperty); }
set { SetValue(IsLoadingProperty, value); }
}
// Using a DependencyProperty as the backing store for IsLoading. This enables animation, styling, binding, etc...
public static readonly DependencyProperty IsLoadingProperty =
DependencyProperty.Register("IsLoading", typeof(bool), typeof(LoadingControl), new UIPropertyMetadata(false));
ControlTemplate - Defined in generic.xaml in the style for {x:Type local:LoadingControl}
<ControlTemplate TargetType="{x:Type local:LoadingControl}">
<ControlTemplate.Triggers>
<Trigger Property="IsLoading" Value="True">
<Trigger.EnterActions>
<RemoveStoryboard BeginStoryboardName="EndAnimateLoadingCanvas" />
<BeginStoryboard Name="AnimateLoadingCanvas">
<Storyboard FillBehavior="Stop">
<ObjectAnimationUsingKeyFrames BeginTime="00:00:00"
Storyboard.TargetName="MyViewBoxje"
Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame Value="{x:Static Visibility.Visible}" />
</ObjectAnimationUsingKeyFrames>
<DoubleAnimation BeginTime="00:00:00"
Duration="00:00:00.5"
Storyboard.TargetName="MyViewBoxje"
Storyboard.TargetProperty="Opacity"
From="0"
To="1" />
<DoubleAnimation BeginTime="00:00:00"
Duration="00:00:02"
Storyboard.TargetName="AnimatedRotateTransform"
Storyboard.TargetProperty="Angle"
From="360"
To="0"
RepeatBehavior="Forever" />
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<RemoveStoryboard BeginStoryboardName="AnimateLoadingCanvas" />
<BeginStoryboard Name="EndAnimateLoadingCanvas">
<Storyboard FillBehavior="Stop">
<DoubleAnimation BeginTime="00:00:00"
Duration="00:00:00.5"
Storyboard.TargetName="MyViewBoxje"
Storyboard.TargetProperty="Opacity"
From="1"
To="0" />
<ObjectAnimationUsingKeyFrames BeginTime="00:00:00.5"
Storyboard.TargetName="MyViewBoxje"
Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame Value="{x:Static Visibility.Collapsed}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
</ControlTemplate.Triggers>
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<Viewbox x:Name="MyViewBoxje" Opacity="0">
<!-- BG with 0x50 alpha so that it's translucent event at 100% visibility -->
<Grid Width="100" Height="100" Background="#50000000">
<Rectangle Width="70" Height="20" Fill="Green" Stroke="Black" StrokeThickness="2" RenderTransformOrigin="0.5,0.5">
<Rectangle.RenderTransform>
<RotateTransform Angle="360" x:Name="AnimatedRotateTransform" />
</Rectangle.RenderTransform>
</Rectangle>
</Grid>
</Viewbox>
</Border>
</ControlTemplate>
I used in my main window like so:
<Grid x:Name="LayoutRoot">
<!-- All other stuff here ... -->
<my:LoadingControl IsLoading="{Binding IsLoading}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
</Grid>
And to test it I had a ViewModel with a property IsLoading that is set as DataContext for the main window. And in the constructor of the ViewModel I set IsLoading to true and then start a timer that toggles the value of the property every 5 seconds:
public MainWindowViewModel()
{
IsLoading = true;
DispatcherTimer t = new DispatcherTimer();
t.Interval = TimeSpan.FromSeconds(5);
t.Tick += (s, e) => IsLoading = !IsLoading;
t.Start();
}
I finally figured it out after reading Isak's answer.
Sorry to say that his answer did not help in my case but he got me going in the right direction.
The reason that the first fade-in did not seem to work was because my containing viewbox had it's visibility set to collapsed the whole time the fade-in animation was performed.
This was caused by the ObjectAnimationUsingKeyFrames:
DiscreteObjectKeyFrame Value="{x:Static Visibility.Visible}" />
</ObjectAnimationUsingKeyFrames>
There was no duration specified and the single key frame specified was animated too late.
Adding
Duration="00:00:00"
solved my problem.
Thanks to you all helping!