I have a Control that can be moved on by dragging. when i drag the control i have a code behind that changes a DependencyProperty that a TranslateTransform is bound to.
now i need to add a button that when is pressed it moves the control, and needs to update the DependencyProperty. I can move the control but can't figure out how to update the DependencyProperty.
code behind:
public partial class AirspeedIndicatorView : UserControl
{
public static readonly DependencyProperty WantedValueProperty =
DependencyProperty.Register("WantedValue", typeof(double), typeof(AirspeedIndicatorView),
new FrameworkPropertyMetadata(0.0, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, WantedPropertyChanged));
public double WantedValue
{
get { return (double)GetValue(WantedValueProperty); }
set { SetValue(WantedValueProperty, value); }
}
private void Thumb_DragDelta(object sender, System.Windows.Controls.Primitives.DragDeltaEventArgs e)
{
WantedValue += e.VerticalChange;
}
}
XAML:
<Thumb Canvas.Top="-6" Height="12" Width="16" DragDelta="Thumb_DragDelta" x:Name="WantedThumb">
<Thumb.RenderTransform>
<TranslateTransform Y="{Binding WantedValue,ElementName=View}" />
</Thumb.RenderTransform>
</Thumb>
<Button Padding="1" Margin="1">
<Button.Style>
<Style TargetType="{x:Type Button}" BasedOn="{StaticResource {x:Type Button}}">
<Setter Property="OverridesDefaultStyle" Value="False" />
<Style.Triggers>
<Trigger Property="IsPressed" Value="True">
<Trigger.EnterActions>
<BeginStoryboard x:Name="MoveWanted">
<Storyboard Target="{x:Reference WantedThumb}" TargetProperty="RenderTransform.Y" AutoReverse="False">
<DoubleAnimation BeginTime="00:00:00" Duration="0:0:0" By="-1" />
<DoubleAnimation BeginTime="00:00:00.5" Duration="0:0:1.5" By="-15" />
<DoubleAnimation BeginTime="00:00:02" Duration="0:0:1" By="-20" RepeatBehavior="Forever" />
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
</Trigger>
<Trigger Property="IsPressed" Value="False">
<Trigger.EnterActions>
<StopStoryboard BeginStoryboardName="MoveWanted" />
</Trigger.EnterActions>
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
I don't have time to check it now, but you should be able to use the ObjectAnimationUsingKeyFrames class to update your DependencyProperty:
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Saved">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<System:Double>10.0</System:Double>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
Actually, the DoubleAnimationUsingKeyFrames class might be better for you as it is intended to work with doubles, but the only down side is that I don't believe that you can data bind the numerical value, so it would have to be a hard coded value. From the last linked page:
<DoubleAnimationUsingKeyFrames
Storyboard.TargetName="AnimatedTranslateTransform"
Storyboard.TargetProperty="X"
Duration="0:0:6"
RepeatBehavior="Forever">
<!-- Using a LinearDoubleKeyFrame, the rectangle moves
steadily from its starting position to 500 over
the first 3 seconds. -->
<LinearDoubleKeyFrame Value="500" KeyTime="0:0:3" />
<!-- Using a DiscreteDoubleKeyFrame, the rectangle suddenly
appears at 400 after the fourth second of the animation. -->
<DiscreteDoubleKeyFrame Value="400" KeyTime="0:0:4" />
<!-- Using a SplineDoubleKeyFrame, the rectangle moves
back to its starting point. The
animation starts out slowly at first and then speeds up.
This KeyFrame ends after the 6th
second. -->
<SplineDoubleKeyFrame KeySpline="0.6,0.0 0.9,0.00" Value="0" KeyTime="0:0:6" />
</DoubleAnimationUsingKeyFrames>
Related
I've made a click event/method that alters the opacity and IsEnabled properties of a textbox.
private void EditButton(object sender, RoutedEventArgs e)
{
religionTB.IsEnabled = true;
DoubleAnimation fade = new
DoubleAnimation(1,TimeSpan.FromSeconds(0.2));
religionTB.BeginAnimation(OpacityProperty, fade);
}
In my WPF project, there are multiple textboxes, I'd like to apply this method to all these textboxes without having to list all of them in the method. How would I go by this?
You can achieve this by using a Style. To do so, go to the context of your event handler (Control or Window) and add a DependencyProperty, to flag the enabled mode and bind a ToggleButton (the edit button) to it that sets this property to enable/ disable the controls and to trigger a fade in and fade out animation:
In your control:
public static readonly DependencyProperty IsEditEnabledProperty = DependencyProperty.Register(
"IsEditEnabled",
typeof(bool),
typeof(MainWindow),
new PropertyMetadata(default(bool)));
public bool IsEditEnabled { get { return (bool) GetValue(MainWindow.IsEditEnabledProperty); } set { SetValue(MainWindow.IsEditEnabledProperty, value); } }
In your XAML add the TextBox style and link a ToggleButton to IsEditEnabled:
<Window.Resources>
<Style x:Key="OpacityStyle" TargetType="TextBox">
<Setter Property="Opacity" Value="0" />
<Setter Property="IsEnabled"
Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=Window}, Path=IsEditEnabled}" />
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=Window}, Path=IsEditEnabled}"
Value="True">
<! Fade in animation -->
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Opacity"
BeginTime="0:0:0"
From="0"
To="1"
Duration="0:0:0.2" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<! Fade out animation -->
<DataTrigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Opacity"
BeginTime="0:0:0"
From="1"
To="0"
Duration="0:0:0.2" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Grid>
<StackPanel>
<ToggleButton x:Name="EditButton" IsChecked="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=Window}, Path=IsEditEnabled, Mode=TwoWay}" />
<TextBox x:Name="AnimatedTextBox" Style="{StaticResource TextBoxAnimationStyle}" >
<TextBox x:Name="AnotherAnimatedTextBox" Style="{StaticResource TextBoxAnimationStyle}" >
<TextBox x:Name="NonanimatedTextBox" >
</StackPanel>
</Grid>
If you make the Style implicit by removing the x:Key attribute, it will apply to all TextBox elements within the scope
I have a static loader image in wpf, I can easily use it as a loading gif by using WPFAnimatedGIF nuget package, but it seems like an overkill.
There is only one scenario in my application where I want to display a busy indicator.
There is nothing to trigger, it is a hidden object in my window and upon certain condition it becomes visible. Thus it should always rotate and appear like a normal animated loading gif.
What I have tried so far
<Image RenderTransformOrigin=".5,.5" Width="44" Height="44" Source="BusyIndicator.gif">
<Image.RenderTransform>
<RotateTransform Angle="45" />
</Image.RenderTransform>
</Image>
Image that I am using is
This Style animates the Angle of a RotateTransform in 30 degree steps when the Image element is visible.
<Style TargetType="Image" x:Key="BusyIndicatorStyle">
<Setter Property="Width" Value="44"/>
<Setter Property="Height" Value="44"/>
<Setter Property="Source" Value="BusyIndicator.png"/>
<Setter Property="RenderTransformOrigin" Value="0.5,0.5"/>
<Setter Property="RenderTransform">
<Setter.Value>
<RotateTransform/>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsVisible" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard RepeatBehavior="Forever">
<DoubleAnimationUsingKeyFrames
Storyboard.TargetProperty="RenderTransform.Angle">
<DiscreteDoubleKeyFrame KeyTime="0:0:0.1" Value="30"/>
<DiscreteDoubleKeyFrame KeyTime="0:0:0.2" Value="60"/>
<DiscreteDoubleKeyFrame KeyTime="0:0:0.3" Value="90"/>
<DiscreteDoubleKeyFrame KeyTime="0:0:0.4" Value="120"/>
<DiscreteDoubleKeyFrame KeyTime="0:0:0.5" Value="150"/>
<DiscreteDoubleKeyFrame KeyTime="0:0:0.6" Value="180"/>
<DiscreteDoubleKeyFrame KeyTime="0:0:0.7" Value="210"/>
<DiscreteDoubleKeyFrame KeyTime="0:0:0.8" Value="240"/>
<DiscreteDoubleKeyFrame KeyTime="0:0:0.9" Value="270"/>
<DiscreteDoubleKeyFrame KeyTime="0:0:1.0" Value="300"/>
<DiscreteDoubleKeyFrame KeyTime="0:0:1.1" Value="330"/>
<DiscreteDoubleKeyFrame KeyTime="0:0:1.2" Value="360"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
</Trigger>
</Style.Triggers>
</Style>
...
<Image Style="{StaticResource BusyIndicatorStyle}" />
In order to avoid using an animation with many DiscreteDoubleKeyFrames, you may derive from DoubleAnimation and add a Step property:
public class DoubleAnimationWithSteps : DoubleAnimation
{
public static readonly DependencyProperty StepProperty = DependencyProperty.Register(
nameof(Step), typeof(double), typeof(DoubleAnimationWithSteps));
public double Step
{
get { return (double)GetValue(StepProperty); }
set { SetValue(StepProperty, value); }
}
protected override double GetCurrentValueCore(
double from, double to, AnimationClock animationClock)
{
var value = base.GetCurrentValueCore(from, to, animationClock);
if (Step > 0d)
{
value = Step * Math.Floor(value / Step);
}
return value;
}
protected override Freezable CreateInstanceCore()
{
return new DoubleAnimationWithSteps();
}
}
You would use it like this:
<Storyboard RepeatBehavior="Forever">
<local:DoubleAnimationWithSteps
Storyboard.TargetProperty="RenderTransform.Angle"
Duration="0:0:1.2" To="360" Step="30"/>
</Storyboard>
I know that this question already has an answer, but there is a different approach. Just use ProgressBar and set IsIndeterminate to True:
<ProgressBar Visibility="{Binding IsBusy, Converter={StaticResource BooleanToVisibilityConverter}}" Style="{StaticResource MaterialDesignCircularProgressBar}" IsIndeterminate="True" Width="36"/>
The style is from Material Design In XAML Toolkit. There is no need to use GIFs as busy indicators, I made the same mistake some time ago
I have a static loader image in wpf, I can easily use it as a loading gif by using WPFAnimatedGIF nuget package, but it seems like an overkill.
There is only one scenario in my application where I want to display a busy indicator.
There is nothing to trigger, it is a hidden object in my window and upon certain condition it becomes visible. Thus it should always rotate and appear like a normal animated loading gif.
What I have tried so far
<Image RenderTransformOrigin=".5,.5" Width="44" Height="44" Source="BusyIndicator.gif">
<Image.RenderTransform>
<RotateTransform Angle="45" />
</Image.RenderTransform>
</Image>
Image that I am using is
This Style animates the Angle of a RotateTransform in 30 degree steps when the Image element is visible.
<Style TargetType="Image" x:Key="BusyIndicatorStyle">
<Setter Property="Width" Value="44"/>
<Setter Property="Height" Value="44"/>
<Setter Property="Source" Value="BusyIndicator.png"/>
<Setter Property="RenderTransformOrigin" Value="0.5,0.5"/>
<Setter Property="RenderTransform">
<Setter.Value>
<RotateTransform/>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsVisible" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard RepeatBehavior="Forever">
<DoubleAnimationUsingKeyFrames
Storyboard.TargetProperty="RenderTransform.Angle">
<DiscreteDoubleKeyFrame KeyTime="0:0:0.1" Value="30"/>
<DiscreteDoubleKeyFrame KeyTime="0:0:0.2" Value="60"/>
<DiscreteDoubleKeyFrame KeyTime="0:0:0.3" Value="90"/>
<DiscreteDoubleKeyFrame KeyTime="0:0:0.4" Value="120"/>
<DiscreteDoubleKeyFrame KeyTime="0:0:0.5" Value="150"/>
<DiscreteDoubleKeyFrame KeyTime="0:0:0.6" Value="180"/>
<DiscreteDoubleKeyFrame KeyTime="0:0:0.7" Value="210"/>
<DiscreteDoubleKeyFrame KeyTime="0:0:0.8" Value="240"/>
<DiscreteDoubleKeyFrame KeyTime="0:0:0.9" Value="270"/>
<DiscreteDoubleKeyFrame KeyTime="0:0:1.0" Value="300"/>
<DiscreteDoubleKeyFrame KeyTime="0:0:1.1" Value="330"/>
<DiscreteDoubleKeyFrame KeyTime="0:0:1.2" Value="360"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
</Trigger>
</Style.Triggers>
</Style>
...
<Image Style="{StaticResource BusyIndicatorStyle}" />
In order to avoid using an animation with many DiscreteDoubleKeyFrames, you may derive from DoubleAnimation and add a Step property:
public class DoubleAnimationWithSteps : DoubleAnimation
{
public static readonly DependencyProperty StepProperty = DependencyProperty.Register(
nameof(Step), typeof(double), typeof(DoubleAnimationWithSteps));
public double Step
{
get { return (double)GetValue(StepProperty); }
set { SetValue(StepProperty, value); }
}
protected override double GetCurrentValueCore(
double from, double to, AnimationClock animationClock)
{
var value = base.GetCurrentValueCore(from, to, animationClock);
if (Step > 0d)
{
value = Step * Math.Floor(value / Step);
}
return value;
}
protected override Freezable CreateInstanceCore()
{
return new DoubleAnimationWithSteps();
}
}
You would use it like this:
<Storyboard RepeatBehavior="Forever">
<local:DoubleAnimationWithSteps
Storyboard.TargetProperty="RenderTransform.Angle"
Duration="0:0:1.2" To="360" Step="30"/>
</Storyboard>
I know that this question already has an answer, but there is a different approach. Just use ProgressBar and set IsIndeterminate to True:
<ProgressBar Visibility="{Binding IsBusy, Converter={StaticResource BooleanToVisibilityConverter}}" Style="{StaticResource MaterialDesignCircularProgressBar}" IsIndeterminate="True" Width="36"/>
The style is from Material Design In XAML Toolkit. There is no need to use GIFs as busy indicators, I made the same mistake some time ago
is it possible to create a c# animation for the AttachedPropertys like Alignment? Maybe 1 Second Move between the Change from HorizontalAlignment.Left to HorizontalAlignment.Right - is it possible?
Thanks a lot.
You can't animate it in the sense of producing a smooth animation where something slides from left to right since they are discrete states. There aren't any in-between values. It is possible to create an "animation" which changes the alignment at some point from left to right, it just won't slide across. You could also do a lot of work and measure all the controls to manually create an animation which moves something from one side of the screen to the other using things like Canvas.Left or margins to position the controls.
The attached property part is not an issue, just use the full name of the attached property in the target property part of your animation.
While it's not possible to directly animate smoothly between two properties like
HorizontalAlignment="Right" VerticalAlignment="Bottom"
to
HorizontalAlignment="Center" VerticalAlignment="Center"
I did come up with a way to do this for an app in a way that I thought might be worth sharing. I simply placed the control in a grid that took up the full pane of the window. I aligned the control to the bottom right of the grid. Then I animated the grid with to transform and scale the corner down that I need to the point I want to align the control too (center in this example. See the complete code below.
<Grid Margin="5,5,14,70" Visibility="{Binding Path=AdminModeIsEnabled, Converter={StaticResource CollapsedVisibilityConverter}, FallbackValue=Visible}">
<Grid.Style>
<Style TargetType="Grid">
<Setter Property="LayoutTransform">
<Setter.Value>
<ScaleTransform/>
</Setter.Value>
</Setter>
<Setter Property="RenderTransform">
<Setter.Value>
<ScaleTransform/>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding CenterPanel}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="(LayoutTransform).(ScaleTransform.ScaleY)" To="2" Duration="0:0:0.5" />
<DoubleAnimation Storyboard.TargetProperty="(RenderTransform).(ScaleTransform.ScaleY)" To=".5" Duration="0:0:0.5" />
<DoubleAnimation Storyboard.TargetProperty="(LayoutTransform).(ScaleTransform.ScaleX)" To="2" Duration="0:0:0.5" />
<DoubleAnimation Storyboard.TargetProperty="(RenderTransform).(ScaleTransform.ScaleX)" To=".5" Duration="0:0:0.5" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="(LayoutTransform).(ScaleTransform.ScaleY)" To="1" Duration="0:0:0.5" />
<DoubleAnimation Storyboard.TargetProperty="(RenderTransform).(ScaleTransform.ScaleY)" To="1" Duration="0:0:0.5" />
<DoubleAnimation Storyboard.TargetProperty="(LayoutTransform).(ScaleTransform.ScaleX)" To="1" Duration="0:0:0.5" />
<DoubleAnimation Storyboard.TargetProperty="(RenderTransform).(ScaleTransform.ScaleX)" To="1" Duration="0:0:0.5" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Grid.Style>
<Image Height="15" Source="\Images\Test.png" HorizontalAlignment="Right" VerticalAlignment="Bottom" />
</Grid>
It is possible, here is an example:
class StoryBoardManager : System.Windows.Media.Animation.Storyboard
{
public void ChangeRectangleAlignment(DependencyObject target, VerticalAlignment verticalAlignment, HorizontalAlignment horizontalAlignment, int BeginTimeMillisecond)
{
ObjectAnimationUsingKeyFrames objectAnimation = new ObjectAnimationUsingKeyFrames()
{
BeginTime = TimeSpan.FromMilliseconds(0)
};
Storyboard.SetTarget(objectAnimation, target);
Storyboard.SetTargetProperty(objectAnimation, new PropertyPath("(FrameworkElement.HorizontalAlignment)"));
DiscreteObjectKeyFrame keyFrame = new DiscreteObjectKeyFrame(horizontalAlignment, TimeSpan.FromMilliseconds(BeginTimeMillisecond));
objectAnimation.KeyFrames.Add(keyFrame);
this.Children.Add(objectAnimation);
}
}
For more information, see this other question.
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!