I have the following in a style for a button, which is used for a refresh button - when the user hovers the mouse over the button, the image on it (in this case a circular arrow) spins around:
<Style x:Key="RefreshButton" TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid Name="buttonContent">
<Image Source="/View/Images/Retry Green2.png" x:Name="Picture" RenderTransformOrigin="0.5,0.5">
<Image.RenderTransform>
<RotateTransform x:Name="AnimatedRotateTransform" Angle="0" />
</Image.RenderTransform>
<Image.Triggers>
<EventTrigger RoutedEvent="MouseEnter">
<BeginStoryboard Name="Spinner">
<Storyboard>
<DoubleAnimation Storyboard.TargetName="AnimatedRotateTransform"
Storyboard.TargetProperty="Angle"
From="0" To="360" Duration="0:0:1"
RepeatBehavior="Forever"
/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="MouseLeave">
<StopStoryboard BeginStoryboardName="Spinner"/>
</EventTrigger>
</Image.Triggers>
</Image>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsPressed" Value="True">
<Setter Property="RenderTransform" TargetName="buttonContent">
<Setter.Value>
<TranslateTransform X="0" Y="2"/>
</Setter.Value>
</Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
When the user moves their mouse away from the button, it stops spinning, which is good, but it also reverts to its original position at zero rotation (the same happens when the user clicks the button). Is there any way, within the style, to change the behaviour so that it stops spinning and remains at its new rotation orientation, both when the user moves the mouse away or when they click the button and it transforms down two points in the second RenderTransform?
The animation should pick up where it left off if the user mouse-overs the button another time.
I know it's a really small thing, but it is a niggle that won't go away and each time I use this template I have another stab at solving the problem without success. I can't help but think I am missing something. I am not helped by the fact that all the related problems I find are to do with animations not stopping at all - narrowing down the searches has proved very difficult.
I believe you are looking for this:
https://learn.microsoft.com/en-us/dotnet/api/system.windows.media.animation.doubleanimation.isadditive?view=net-5.0
To add to your DoubleAnimation.
EDIT: This coupled with replacing StopStoryBoard with PauseStoryBoard should solve the problem. The final xaml should look like this in the Image.Triggers node:
<Image.Triggers>
<EventTrigger RoutedEvent="MouseEnter">
<BeginStoryboard Name="Spinner">
<Storyboard>
<DoubleAnimation Storyboard.TargetName="AnimatedRotateTransform"
Storyboard.TargetProperty="Angle"
IsAdditive="true"
From="0" To="360" Duration="0:0:1"
RepeatBehavior="Forever"
/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="MouseLeave">
<PauseStoryboard BeginStoryboardName="Spinner"/>
</EventTrigger>
</Image.Triggers>
Related
I want to animate the width of a control(the Rectangle here). This code does animate the width and auto revereses the width back to its original but not if i trigger the animation again midway. In that case the width auto reverses to the width when I retriggered it, never going back to its original width.
And giving the animation a "From" property requires me to remember the original width and it is not runtime width, it just stays being that. Cant find a way to bind to the Rectangle width or something.
Like saying <DoubleAnimation From="rectangle.Width"/>
<Style x:Key="animation" TargetType="ContentControl">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid>
<Rectangle x:Name="rectangle" Fill="Blue" Width="500"></Rectangle>
</Grid>
<ControlTemplate.Triggers>
<EventTrigger RoutedEvent="MouseDown">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="rectangle" Storyboard.TargetProperty="Width"
To="250" Duration="0:0:1" AutoReverse="True"></DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I think binding the rectangle element width to the the "From" property in the animation will solve all the problem. Because it will always auto reverse back to that.
Acually I tried From="{Binding ElementName=rectangle,Path=Width}". its a valid xaml code. But after build errors it says
Error Cannot freeze this Storyboard timeline tree for use across threads.
Instead of animation the Rectangle's Width and hence deal with absolute size values, you may better animate a ScaleTransform, e.g. like this:
<ControlTemplate>
<Grid>
<Rectangle x:Name="rectangle" Fill="Blue" Width="500"
RenderTransformOrigin="0.5,0.5">
<Rectangle.RenderTransform>
<ScaleTransform/>
</Rectangle.RenderTransform>
</Rectangle>
</Grid>
<ControlTemplate.Triggers>
<EventTrigger RoutedEvent="MouseDown">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="rectangle"
Storyboard.TargetProperty="RenderTransform.ScaleX"
From="1" To="0.5" Duration="0:0:1" AutoReverse="True"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
I'm trying to make a "Please wait" animation. It could consist of 4 Rectangles having the exact same animation, but slightly delayed.
Here's one of them:
<Rectangle Fill="Blue" Margin="4">
<Rectangle.Style>
<Style TargetType="Rectangle">
<Setter Property="RenderTransform">
<Setter.Value>
<ScaleTransform/>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="Visibility" Value="Visible">
<Trigger.EnterActions>
<BeginStoryboard x:Name="FlipIt">
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="RenderTransform.ScaleY" From="1" To="0" Duration="0:0:1" RepeatBehavior="Forever"/>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<StopStoryboard BeginStoryboardName="FlipIt"/>
</Trigger.ExitActions>
</Trigger>
</Style.Triggers>
</Style>
</Rectangle.Style>
</Rectangle>
(I used a trigger on Visibility so it doesn't eat up CPU uselessly)
So basically, what I could do is to simply copy paste these 24 lines of XAML Style for each of my Rectangles. But what if I decided that 9 rectangles look better? That's gonna get nuts pretty fast.
My idea was to have, in my Window's Resources, this style, and in each Rectangle's Resources, a DoubleAnimation for whatever it wants to do (in the case of 9 Rectangles, I may want the middle one to spin instead of scale on its Y axis).
The question is then: how can I reference a Rectangle's DoubleAnimation (given the fact that they'd all have the same x:Key) inside my Style's Storyboard (contained in my Window's Resources)?
Edit 1:
Here's how I think it should go:
Window's resources:
A style named "AnimIt"...
<Style.Triggers>
<Trigger Property="Visibility" Value="Visible">
<Trigger.EnterActions>
<BeginStoryboard x:Name="FlipIt">
<Storyboard Children="?????????????"/>
</BeginStoryboard>
</Trigger.EnterActions>
...
A Rectangle:
<Rectangle Style="{StaticResource AnimIt}">
<Rectangle.Resources>
<DoubleAnimation x:Key="anim" Storyboard.TargetProperty="RenderTransform.ScaleY" From="1" To="0" Duration="0:0:1" RepeatBehavior="Forever"/>
</Rectangle.Resources>
I dont really know what to put in place of the "????????". I tried playing with RelativeSource FindAncestor, but have no idea how to reference the DoubleAnimation there.
I have a (lame) user requirement to make a control super visible.
Sadly that means a flashing background (Ug).
So, the control is a Border that holds a TextBlock is only visible in fairly rare scenarios.
I have looked at a few animation examples and they all have a "Trigger" on them. Most commonly when the user clicks on something.
Is there a way to just have the animation running all the time (if the control is visible of course)?
here you go, RepeatBehavior="Forever" will keep the animation running until stopped or removed
you can trigger a color animation with auto reverse enabled on the control load and let it run forever
<Border Background="Transparent">
<TextBlock Text="some text" />
<Border.Triggers>
<EventTrigger RoutedEvent="Loaded">
<BeginStoryboard>
<Storyboard>
<ColorAnimation To="SkyBlue"
Storyboard.TargetProperty="Background.Color"
RepeatBehavior="Forever"
AutoReverse="True" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Border.Triggers>
</Border>
if you need the animation to be triggered on visibility change then here is a way, note that the animation is applied when IsVisible property become true and stopped when it become false.
<Border Background="Transparent">
<TextBlock Text="some text" />
<Border.Style>
<Style TargetType="Border">
<Style.Triggers>
<Trigger Property="IsVisible"
Value="true">
<Trigger.EnterActions>
<BeginStoryboard x:Name="startFlashing">
<Storyboard>
<ColorAnimation To="SkyBlue"
Storyboard.TargetProperty="Background.Color"
RepeatBehavior="Forever"
AutoReverse="True" />
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<StopStoryboard BeginStoryboardName="startFlashing" />
</Trigger.ExitActions>
</Trigger>
</Style.Triggers>
</Style>
</Border.Style>
</Border>
typically after visibility is set to false there is no visible difference if animation is still running or stopped.
When I put my mouse on 1st image, 2nd image will appear. When I leave my mouse on 1st image, 2nd image will straight away fade off. How to do to make 2nd image to keep on appear for a few second even after l leave off my mouse on the 1st image?
<EventTrigger RoutedEvent="Button.Click" SourceName="P">
<EventTrigger.Actions>
<BeginStoryboard Storyboard="{StaticResource showA}"/>
</EventTrigger.Actions>
</EventTrigger>
<Button Grid.Column="1" Command="{Binding Path=PressC}" CommandParameter="cam" Style="{StaticResource TransparentButton}">
<Button.Template>
<ControlTemplate TargetType="{x:Type Button}">
<Grid>
<Image Name="1" Source="/W;component/Images/1.png" Height="100" />
<Image Name="2" Source="/W;component/Images/2.png" Height="200" Width="100" Margin="50,-33,-50,0" Visibility="Hidden" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="imgPressedKeyboard05" Storyboard.TargetProperty="Opacity" From="0" To="2" Duration="0:0:.5" BeginTime="0:0:0"/>
<DoubleAnimation Storyboard.TargetName="imgPressedKeyboard05" Storyboard.TargetProperty="Opacity" From="2" To="0" Duration="0:0:.5" BeginTime="0:0:1"/>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Setter Property="Panel.ZIndex" Value="999"/>
<Setter TargetName="pressed5" Property="Visibility" Value="Visible"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Button.Template>
</Button>
Use animations instead of a simple Setter. One in the EnterActions to make it visible, one in the ExitActions to hide it after a given time. To animate Visibility you can use an ObjectAnimationUsingKeyFrames.
I am trying to animate an error message popup to expand itself slightly then contract to its original size all in about a half second interval to give emphasis to it in WPF. The window is designed as a border with another border inside that houses a stack panel with an icon on the left and a messagebox to the right. On initialization the messagebox gets the exception populated and the whole window's size is set to sizetocontent. By the way I am using .NET 3.5. Please help!
Add this to your xaml within the outside Border or to the Window
<Style>
<Setter Property="Border.RenderTransform">
<Setter.Value>
<ScaleTransform CenterX="50" CenterY="50" ScaleX="1" ScaleY="1" />
</Setter.Value>
</Setter>
<Style.Triggers>
<EventTrigger RoutedEvent="Border.Loaded">
<EventTrigger.Actions>
<BeginStoryboard >
<Storyboard>
<DoubleAnimation Duration="0:0:0.5"
Storyboard.TargetProperty="RenderTransform.ScaleX"
From="1.0" To="1.1" Duration="0:0:0.5"
AutoReverse="True"/>
<DoubleAnimation Duration="0:0:0.5"
Storyboard.TargetProperty="RenderTransform.ScaleY"
From="1.0" To="1.1" Duration="0:0:0.5"
AutoReverse="True"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Style.Triggers>
</Style>