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>
Related
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>
I have ListBox:
<ListBox x:Name="ListBoxImages"
ScrollViewer.CanContentScroll="True"
UseLayoutRounding="False"
SelectionMode="Extended"/>
ListBox style:
<Style TargetType="{x:Type ListBox}">
...
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBox">
<Border Name="Border">
<ScrollViewer Focusable="false">
<WrapPanel ItemWidth="100"
IsItemsHost="True"/>
</ScrollViewer>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
and ListBoxItem style (animation here, sorry for long code):
<Style TargetType="{x:Type ListBoxItem}">
<!--...-->
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<Border x:Name="border"
RenderTransformOrigin="0.5,0.5">
<Border.RenderTransform>
<TransformGroup>
<ScaleTransform x:Name="ScaleTransform"/>
</TransformGroup>
</Border.RenderTransform>
<ContentPresenter/>
</Border>
<!--Animation-->
<EventTrigger RoutedEvent="FrameworkElement.Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="ScaleTransform"
Storyboard.TargetProperty="ScaleX"
Duration="0:0:0.1"
From="0" To="1"/>
<DoubleAnimation Storyboard.TargetName="ScaleTransform"
Storyboard.TargetProperty="ScaleY"
Duration="0:0:0.1"
From="0" To="1"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="FrameworkElement.Unloaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="ScaleTransform"
Storyboard.TargetProperty="ScaleX"
Duration="0:0:0.1"
To="0"/>
<DoubleAnimation Storyboard.TargetName="ScaleTransform"
Storyboard.TargetProperty="ScaleY"
Duration="0:0:0.1"
To="0"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Question. Animations when adding the element (FrameworkElement.Loaded) played not always. Such feeling that it is played when an item has been created, but not yet displayed.
The animation when item is deleted (FrameworkElement.Unloaded) does not play.
So, how to fix it?
Your Loaded storyboard is defined correctly, thus there should be other reasons why it is sometimes played correctly and sometimes not. Is there a long-living operation on the UI thread when a new item is added to the list box? This would result in a freeze so that the animation is not played fluently all the time.
Your Unloaded storyboard is not played because this event is raised when the element is removed from the visual / logical tree that is used to render the whole scene. This storyboard should be started before this removal but unfortunately there is no mechanism / event that tells that an item is to be removed.
Currently there is no easy way to fade out an item from an ItemsControl in WPF. In WinRT and Silverlight, there are two separate visual states for ItemsControl items that you can use for fade-in or fade-out. As Krishna mentioned, the only way is to implement custom functionality to tell an item that it is about to be removed and that it should run the fade-out animation. After that animation, the item can be removed from the visual / logical tree.
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.
I am trying to create a designer like Visual Studio.
Suppose I have a Grid.
Inside that I have a TextBox and a TextBlock. For better understanding look at the sample code below:
<Page.Resources>
<Style x:Key="myStyle" TargetType="{x:Type Border}">
<Setter Property="BorderBrush" Value="Transparent" />
<Setter Property="BorderThickness" Value="2" />
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="BorderBrush" Value="DodgerBlue" />
</Trigger>
</Style.Triggers>
</Style>
</Page.Resources>
<Border Style="myStyle">
<Grid>
<Border Style="myStyle">
<TextBox ...... />
</Border>
<Border Style="myStyle">
<TextBlock ...... />
</Border>
</Grid>
</Border>
Now when I mouseOver on any of the element I want to get a border around it.
My Problems:
I get a border around grid as well as a border around textblock when mouse cursor is over textblock.
When my mouse cursor goes over empty area of grid the border is not shown.
Requirements :
when mouse cursor goes over textblock, the border around grid should become invisible.
when mouse cursor goes over empty area in grid, the border around grid should become visible.
Please suggest the changes that I should make in the above code to have the required functionality.
Why did you assign myStyle to the outter Border? Just leave that out.
1: I think, your idea with glowing parent border is not good. Because it will be blink whenever user hold mouse over the grid. Perhaps, it will annoy user :)
2: Try to set Grid.Background="Transparent".
Try this
<Grid Background="LightGray" >
<Grid.Triggers>
<EventTrigger RoutedEvent="MouseEnter">
<BeginStoryboard>
<Storyboard >
<DoubleAnimation From="0" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="Grid_Bd" Duration="0:0:0.1"></DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="MouseLeave">
<BeginStoryboard>
<Storyboard >
<DoubleAnimation From="1" To="0" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="Grid_Bd" Duration="0:0:0.1"></DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Grid.Triggers>
<Grid Height="50" Width="50">
<Border x:Name="TextBlock_Bd" Opacity="0" BorderBrush="Blue" BorderThickness="1"/>
<TextBlock Text="Hello !!" HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock.Triggers>
<EventTrigger RoutedEvent="MouseEnter">
<BeginStoryboard>
<Storyboard >
<DoubleAnimation From="0" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="TextBlock_Bd" Duration="0:0:0.1"></DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="MouseLeave">
<BeginStoryboard>
<Storyboard >
<DoubleAnimation From="1" To="0" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="TextBlock_Bd" Duration="0:0:0.1"></DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</TextBlock.Triggers>
</TextBlock>
</Grid>
<Border x:Name="Grid_Bd" Opacity="0" BorderBrush="Red" BorderThickness="1"/>
</Grid>
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.