Can this animation not spam? - wpf

I am pretty new to xaml and wpf in general, so excuse me if the solution is easy or the xaml i used is bad. I am unsure if this is possible, but if there is some kind of solution please let me know!
Here is a video of what i am trying to fix:
https://imgur.com/a/NmnV50S
If the video doesn't explain my problem, here it is: can the button animation not spam or bug when the user moves his cursor very fast across the button?
Here is the xaml for the animation:
<Style x:Key="SlidingButtonToRight" TargetType="Button">
<Setter Property="Width" Value="270"/>
<Setter Property="Height" Value="80"/>
<Setter Property="UseLayoutRounding" Value="True"/>
<Setter Property="ClipToBounds" Value="True"/>
<Setter Property="FontSize" Value="20"/>
<Setter Property="Button.RenderTransform">
<Setter.Value>
<TranslateTransform/>
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border Name="border" BorderThickness="0" BorderBrush="Black" Background="{TemplateBinding Background}">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Opacity" Value="0.8" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<EventTrigger RoutedEvent="MouseEnter">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="(Image.RenderTransform).(TranslateTransform.X)" From="0" To="110" Duration="0:0:0.2" />
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
<EventTrigger RoutedEvent="MouseLeave">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="(Image.RenderTransform).(TranslateTransform.X)" From="110" To="0" Duration="0:0:0.3" />
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Style.Triggers>
</Style>
<Style x:Key="SlidingButtonToLeft" TargetType="Button" BasedOn="{StaticResource SlidingButtonToRight}">
<Style.Triggers>
<EventTrigger RoutedEvent="MouseEnter">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="(Image.RenderTransform).(TranslateTransform.X)" From="0" To="-110" Duration="0:0:0.2" />
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
<EventTrigger RoutedEvent="MouseLeave">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="(Image.RenderTransform).(TranslateTransform.X)" From="-110" To="0" Duration="0:0:0.3" />
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Style.Triggers>
</Style>
Here is the xaml for the button on which i use the animation style:
<Button x:Name="button4" Click="Button4_Click" Style="{DynamicResource SlidingButtonToLeft}" Margin="0,50,-186,0" VerticalAlignment="Top" HorizontalAlignment="Right">
<Button.Background>
<ImageBrush ImageSource="Assets/programm-bt.png"/>
</Button.Background>
<TextBlock Text="Programm" TextAlignment="Left" Width="105" Margin="0,0,-25,0" HorizontalAlignment="Center"/>
</Button>

To reduce the animation spam, you can set a BeginTime property on your MouseLeave animation to give the user enough time to move the mouse off the button before the animation starts.
You can start with .2 seconds and tweak from there:
<Storyboard>
<DoubleAnimation
BeginTime="0:0:0.2"
Storyboard.TargetProperty="(Image.RenderTransform).(TranslateTransform.X)"
From="-110"
To="0"
Duration="0:0:0.3" />
</Storyboard>

I figured it out, by removing From ,the animation doesn't start from 0 every time the user hovers over the button. Here is a video from before and after the change.
<Style.Triggers>
<EventTrigger RoutedEvent="MouseEnter">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="(Image.RenderTransform).(TranslateTransform.X)"
To="110"
Duration="0:0:0.2"
/>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
<EventTrigger RoutedEvent="MouseLeave">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetProperty="(Image.RenderTransform).(TranslateTransform.X)"
To="0"
Duration="0:0:0.3" />
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Style.Triggers>

Related

Animate newly added item in Listbox

I am trying to add animation to newly added item and/or changed item in my listbox, this is what i've done so far:
<Style x:Key="ListBoxItemStyle4" TargetType="{x:Type ListBoxItem}">
<Setter Property="LayoutTransform">
<Setter.Value>
<ScaleTransform x:Name="transform" />
</Setter.Value>
</Setter>
<Style.Triggers>
<EventTrigger RoutedEvent="Loaded">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Opacity" From="0" To="1" Duration="0:0:2" />
<DoubleAnimation Storyboard.TargetProperty="LayoutTransform.ScaleY" From="0" Duration="0:0:.2"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Style.Triggers>
</Style>
This animates every item in my listbox.
There's a working example explained in this article:
https://social.technet.microsoft.com/wiki/contents/articles/31416.wpf-mvvm-friendly-user-notification.aspx#Toast
It applies the animation via itemcontainerstyle:
<ListBox ItemsSource="{Binding Messages}" BorderBrush="Transparent" Background="LightGray">
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<ContentPresenter/>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="LayoutTransform">
<Setter.Value>
<ScaleTransform/>
</Setter.Value>
</Setter>
<Style.Triggers>
<EventTrigger RoutedEvent="Loaded">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Opacity" From="0" To="1" Duration="0:0:1.2" FillBehavior="Stop" />
<DoubleAnimation Storyboard.TargetProperty="LayoutTransform.ScaleY" From="0" Duration="0:0:1.2" FillBehavior="Stop">
<DoubleAnimation.EasingFunction>
<BounceEase Bounces="2" Bounciness="6"/>
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
Also addressed is animating before removal.

Why XAML defined animation causes System.InvalidOperationException

I need define simple animation in the XAML (without code behind), that must rotate the background image of button by changing the bounded boolean property. I have a button in the XAML:
<Button Style="{StaticResource btnStyle}" />
In the Resources section of the Window I create following:
<RotateTransform Angle="180" x:Key="rotAt180" />
<Style TargetType="Button" x:Key="btnStyle">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Image Source="Images\pic.png" />
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding MyBoolProp}" Value="False">
<Setter Property="RenderTransform" Value="{StaticResource rotAt180}" />
<!-- This animation works good -->
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation From="0" To="180" Duration="0:0:0.2" Storyboard.TargetProperty="RenderTransform.Angle" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<!-- This animation causes exception -->
<DataTrigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation From="180" To="0" Duration="0:0:0.2" Storyboard.TargetProperty="RenderTransform.Angle" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
MyBoolProp is initialized by True.
The first animation is works perfect. But the second animation causes System.InvalidOperationException in PresentationFramework.dll ("Unable to resolve all property references in the "RenderTransform.Angle" property path. Check that the corresponding objects support such properties").
I tried to move the second animation into the trigger, where MyBoolProp is True:
<DataTrigger Binding="{Binding MyBoolProp}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation From="180" To="0" Duration="0:0:0.2" Storyboard.TargetProperty="RenderTransform.Angle" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
But the result is the same. What is wrong in such realization?
The RenderTransform must be set in the Style, not in the DataTrigger:
<Style TargetType="Button" x:Key="btnStyle">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Image Source="Images\pic.png" />
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="RenderTransform" Value="{StaticResource rotAt180}"/>
<Setter Property="RenderTransformOrigin" Value="0.5,0.5" />
<Style.Triggers>
<DataTrigger Binding="{Binding MyBoolProp}" Value="False">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation To="0" Duration="0:0:0.2"
Storyboard.TargetProperty="RenderTransform.Angle" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation To="180" Duration="0:0:0.2"
Storyboard.TargetProperty="RenderTransform.Angle" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>

How to write a style for a control that changes width of another control?

Is there any way to write a Style for a control that changes width of another control?
<Style x:Key="SubMenuStyle" TargetType="Label">
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="FontFamily" Value="Arial"/>
<Setter Property="FontSize" Value="14"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="BorderBrush" Value="LightCyan"/>
<Style.Triggers>
<EventTrigger RoutedEvent="MouseLeftButtonDown">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="Menu" Storyboard.TargetProperty="Width" To="0" Duration="0:0:.5"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Style.Triggers>
</Style>
This code leads to error:
TargetName property cannot be set on a Style Setter
I know I can write codes below and it works:
<Label Name="Owners" Margin="0,1,0,0" MouseLeftButtonDown="SubMenuClicked" Style="{StaticResource SubMenuStyle}">
<Label.Triggers>
<EventTrigger RoutedEvent="MouseLeftButtonDown">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="Menu" Storyboard.TargetProperty="Width" To="0" Duration="0:0:.5"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Label.Triggers>
</Label>
But since I use this trigger in multiple labels I want to write it in a style once.
This is my code to define controls:
<Border Name="Menu" Grid.Column="2" Grid.Row="1" Width="0" HorizontalAlignment="Right" BorderBrush="LightBlue" BorderThickness="2" CornerRadius="2" Background="LightCyan">
<StackPanel Name="MenuPanel">
<Button Style="{StaticResource MenuButtonsStyle}">
<Button.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="ListsMenu" Storyboard.TargetProperty="Height" To="86" Duration="0:0:.6"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Button.Triggers>
</Button>
<StackPanel Name="ListsMenu" Height="0">
<Label Name="Owners" Margin="0,1,0,0" MouseLeftButtonDown="SubMenuClicked" Style="{StaticResource SubMenuStyle}"/>
<Label Name="Contacts" MouseLeftButtonDown="SubMenuClicked" Style="{StaticResource SubMenuStyle}"/>
<Label Name="Groups" MouseLeftButtonDown="SubMenuClicked" Style="{StaticResource SubMenuStyle}"/>
</StackPanel>
</StackPanel>
</Border>
Scenario: There is a border, It's default width is zero, It will raise to 165 in another trigger which works fine, I want to animate it to zero again when labels are clicked, but I can not access the width of that border in lables style
You claim that you use triggers in multiple labels so you can define trigger one time like this
<Storyboard x:Key="animation">
<DoubleAnimation Storyboard.TargetName="ListsMenu" Storyboard.TargetProperty="Height" To="86" Duration="0:0:.6"/>
</Storyboard>
and later when you need you can call it
<EventTrigger RoutedEvent="MouseEnter" >
<BeginStoryboard Storyboard="{StaticResource animation}"/>
</EventTrigger>
But I'm a bit confused what you meant to acquire.
You cannot get access in style since style does not have a namescope, as it was said. If it changes label's width you could do this in style like this
<Style x:Key="style_button" TargetType="Button">
<Style.Triggers>
<EventTrigger RoutedEvent="MouseEnter">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Width" To="300" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Style.Triggers>
</Style>
but it invokes by StoryBoard.TargetName to another object.
try :
<EventTrigger RoutedEvent="MouseLeftButtonDown">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.Target="{Binding ElementName=Menu}"
Storyboard.TargetProperty="Width" To="0" Duration="0:0:.5"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
TargetName is only valid inside Templates.

Smoothly resize an UIElement

I have a set of Ellipses on my Canvas.
For the MouseEnter event on each of the ellipses, I would like to resize the element so as to give a magnifying look and feel.
To make it more attractive, I want to make the change gradual (smooth/animated feeling). Any hints are appreciated.
Try something like this:
<Style x:Key="ScaleStyle" TargetType="{x:Type FrameworkElement}">
<Setter Property="RenderTransformOrigin" Value="0.5,0.5"/>
<Setter Property="RenderTransform">
<Setter.Value>
<ScaleTransform />
</Setter.Value>
</Setter>
<Style.Triggers>
<EventTrigger RoutedEvent="MouseEnter">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation To="1.2" Duration="0:0:0.2"
Storyboard.TargetProperty="RenderTransform.ScaleX" />
<DoubleAnimation To="1.2" Duration="0:0:0.2"
Storyboard.TargetProperty="RenderTransform.ScaleY" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="MouseLeave">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation To="1.0" Duration="0:0:0.1"
Storyboard.TargetProperty="RenderTransform.ScaleX" />
<DoubleAnimation To="1.0" Duration="0:0:0.1"
Storyboard.TargetProperty="RenderTransform.ScaleY" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Canvas>
<Ellipse Style="{StaticResource ScaleStyle}" Canvas.Left="100" Canvas.Top="100"
Width="200" Height="100" Stroke="Black" StrokeThickness="2" Fill="Transparent" />
</Canvas>

Animating things in WPF - name cannot be found in the name scope of 'System.Windows.Controls.ControlTemplate'

Been trying to make a tabcontrol with some animation when changing tabs but it keeps giving me grief and refusing to let me put the animation in any useful place unless it's in the same XAML window file as the control itself (the style resides in a DLL file from which other styles work). Here's my style:
<Style x:Key="AnimatedTabControl" TargetType="{x:Type TabControl}">
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="Background" Value="White" />
<Setter Property="BorderThickness" Value="0" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabControl}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Border>
<TabPanel
IsItemsHost="True">
</TabPanel>
</Border>
<Border BorderThickness="0"
Grid.Row="1"
BorderBrush="White"
Background="White">
<ContentPresenter x:Name="TabControlContent" ContentSource="SelectedContent" Margin="0" />
</Border>
</Grid>
<ControlTemplate.Resources>
<Storyboard x:Key="TabSelectionChangedStoryboard">
<DoubleAnimation Storyboard.TargetName="TabControlContent"
Storyboard.TargetProperty="Opacity"
To="100"
From="0"
FillBehavior="HoldEnd"
Duration="0:0:30.0" />
</Storyboard>
</ControlTemplate.Resources>
<ControlTemplate.Triggers>
<EventTrigger RoutedEvent="SelectionChanged">
<BeginStoryboard Storyboard="{StaticResource TabSelectionChangedStoryboard}" />
</EventTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
This results in 'TabControlContent' name cannot be found in the name scope of 'System.Windows.Controls.ControlTemplate'
I've also tried to move the animation to the beginning of the file, which results in the same error. If I put it after the style, the storyboard can't find it. Is there any way around this?
Solution:
use Storyboard.Target instead of Storyboard.TargetName in combination with {Binding ElementName=TabControlContent.
replace
<DoubleAnimation
Storyboard.TargetName="TabControlContent"
Storyboard.TargetProperty="Opacity"
To="100"
From="0"
FillBehavior="HoldEnd"
Duration="0:0:30.0" />
with
<DoubleAnimation
Storyboard.Target="{Binding ElementName=TabControlContent}"
Storyboard.TargetProperty="Opacity"
To="100"
From="0"
FillBehavior="HoldEnd"
Duration="0:0:30.0" />
I search on web a lot but did not found appropriate answer... and after four days try Finally completed this way...
<ControlTemplate x:Key="GeneralButton" TargetType="{x:Type Button}">
<Grid>
<Border Background="{StaticResource ButtonGeneral}"
VerticalAlignment="Stretch" CornerRadius="6" HorizontalAlignment="Stretch"/>
<Border x:Name="BorderFocused" Opacity="0" Background="{StaticResource ButtonFocused}"
VerticalAlignment="Stretch" CornerRadius="6" HorizontalAlignment="Stretch"/>
<Border x:Name="BorderPressed" Opacity="0" Background="Purple"
VerticalAlignment="Stretch" CornerRadius="6" HorizontalAlignment="Stretch"/>
<Border x:Name="BorderDisabled" Opacity="0" Background="{StaticResource ButtonDisabled}"
VerticalAlignment="Stretch" CornerRadius="6" HorizontalAlignment="Stretch"/>
<ContentPresenter VerticalAlignment="Center"
HorizontalAlignment="Center" x:Name="MainContent" Margin="20,5" >
<TextElement.Foreground>
<SolidColorBrush Color="White"></SolidColorBrush>
</TextElement.Foreground>
<TextElement.FontSize>
16
</TextElement.FontSize>
</ContentPresenter>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsKeyboardFocused" Value="true">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="BorderFocused" Storyboard.TargetProperty="Opacity" To="1" Duration="0:0:0.01"/>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="BorderFocused" Storyboard.TargetProperty="Opacity" To="0" Duration="0:0:0.4"/>
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
<Trigger Property="IsMouseOver" Value="true">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="BorderFocused" Storyboard.TargetProperty="Opacity" To="1" Duration="0:0:0.01"/>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="BorderFocused" Storyboard.TargetProperty="Opacity" To="0" Duration="0:0:0.4"/>
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="BorderPressed" Storyboard.TargetProperty="Opacity" To="1" Duration="0:0:0.01"/>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="BorderPressed" Storyboard.TargetProperty="Opacity" To="0" Duration="0:0:0.5"/>
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="BorderDisabled" Storyboard.TargetProperty="Opacity" To="1" Duration="0:0:0"/>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="BorderDisabled" Storyboard.TargetProperty="Opacity" To="0" Duration="0:0:0.2"/>
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
I solved the problem using the "VisualStateManager", at the following link you will find a brief explanation of the differences between "VisualStateManager" and "Triggers".
https://stackoverflow.com/a/41030110/13037386
This shows how the graphic states are detached from triggers.

Resources