Smoothly resize an UIElement - wpf

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>

Related

Can this animation not spam?

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>

WPF Rectangle Triggers when Visible for DoubleAnimation StoryBoard

I have a DoubleAnimation which fades in/out a Rectangle in WPF
<Canvas>
<Rectangle Height="150" Width="150">
<Rectangle.Fill>
<SolidColorBrush x:Name="OpacityBrush" Color="DarkBlue" />
</Rectangle.Fill>
<Rectangle.Triggers>
<EventTrigger RoutedEvent="Rectangle.Loaded">
<BeginStoryboard>
<StoryBoard>
<DoubleAnimation Storyboard.TargetName="OpacityBrush" Storyboard.TargetProperty="Opacity" From="0.0" To="0.6" Duration="0:0:5" AutoReverse="True" RepeatBehavior="Forever" />
<DoubleAnimation Storyboard.TargetName="OpacityBrush" Storyboard.TargetProperty="Opacity" From="0.6" To="0.0" Duration="0:0:5" AutoReverse="True" RepeatBehavior="Forever" />
</StoryBoard>
</BeginStoryboard>
</EventTrigger>
</Rectangle.Triggers>
</Rectangle>
</Canvas>
This works fine but I want this to happen only when the rectangle is visible. Currently, it animates (I assume) in the background when it loads.
How can I change it so that it would start animation when it is visible and stop when it is hidden/collapse?
Or does it not matter? I'm just worried that it would take up resources (for the animation) as there are a lot of rectangles in the application and most of the time they are hidden.
Thanks.
Try this
1st Method
<Canvas>
<Rectangle Height="150" Width="150">
<Rectangle.Fill>
<SolidColorBrush x:Name="OpacityBrush" Color="DarkBlue" />
</Rectangle.Fill>
<Rectangle.Triggers>
<EventTrigger RoutedEvent="Rectangle.Loaded">
<BeginStoryboard>
<Storyboard Name="Anm">
<DoubleAnimation Storyboard.TargetName="OpacityBrush" Storyboard.TargetProperty="Opacity" From="0.0" To="0.6" Duration="0:0:5" AutoReverse="True" RepeatBehavior="Forever" />
<DoubleAnimation Storyboard.TargetName="OpacityBrush" Storyboard.TargetProperty="Opacity" From="0.6" To="0.0" Duration="0:0:5" AutoReverse="True" RepeatBehavior="Forever" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Rectangle.Triggers>
<Rectangle.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding Source={RelativeSource Self}, Path=Visibility}" Value="{x:Static Visibility.Collapsed}">
<DataTrigger.EnterActions>
<StopStoryboard BeginStoryboardName="Anm"/>
</DataTrigger.EnterActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Rectangle.Style>
</Rectangle>
</Canvas>
2nd Method
<Canvas>
<Rectangle Height="150" Width="150">
<Rectangle.Fill>
<SolidColorBrush x:Name="OpacityBrush" Color="DarkBlue" />
</Rectangle.Fill>
<Rectangle.Style>
<Style TargetType="Rectangle">
<Style.Triggers>
<Trigger Property="Visibility" Value="Visible">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard Name="Anm">
<DoubleAnimation Storyboard.TargetProperty="Opacity" From="0.0" To="0.6" Duration="0:0:5" AutoReverse="True" RepeatBehavior="Forever" />
<DoubleAnimation Storyboard.TargetProperty="Opacity" From="0.6" To="0.0" Duration="0:0:5" AutoReverse="True" RepeatBehavior="Forever" />
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<StopStoryboard BeginStoryboardName="Anm"></StopStoryboard>
</Trigger.ExitActions>
</Trigger>
</Style.Triggers>
</Style>
</Rectangle.Style>
</Rectangle>
</Canvas>

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.

Generic template for Image with style and triggers

I saw this post
Given a WPF Image control, how can I make it bigger through animation on MouseEnter?
and I was wondering if I want to reuse this code on many Images in my project how can I apply a template to do so?
I tried creating a style but i got exception that I cannot use TargetName in Storyboard.TargetName="scale"
The Code:
<Image Width="100" Height="100" Source="...">
<Image.RenderTransform>
<ScaleTransform
x:Name="scale"
CenterX="50"
CenterY="50"
ScaleX="1"
ScaleY="1" />
</Image.RenderTransform>
<Image.Triggers>
<EventTrigger RoutedEvent="Image.MouseEnter">
<BeginStoryboard>
<BeginStoryboard.Storyboard>
<Storyboard Duration="0:0:0.2">
<DoubleAnimation
Storyboard.TargetName="scale"
Storyboard.TargetProperty="ScaleX"
To="1.5" />
<DoubleAnimation
Storyboard.TargetName="scale"
Storyboard.TargetProperty="ScaleY"
To="1.5" />
</Storyboard>
</BeginStoryboard.Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="Image.MouseLeave">
<BeginStoryboard>
<BeginStoryboard.Storyboard>
<Storyboard Duration="0:0:0.2">
<DoubleAnimation
Storyboard.TargetName="scale"
Storyboard.TargetProperty="ScaleX"
To="1" />
<DoubleAnimation
Storyboard.TargetName="scale"
Storyboard.TargetProperty="ScaleY"
To="1" />
</Storyboard>
</BeginStoryboard.Storyboard>
</BeginStoryboard>
</EventTrigger>
</Image.Triggers>
</Image>
this is not the final answer, but I have been trying since this morning (I have to go now :-) ) but I thought this can lead you to find an answer. I still have a runtime error, but it seems to be on the right path.
<Window.Resources>
<ScaleTransform x:Key="Scale"
CenterX="50"
CenterY="50"
ScaleX="1.5"
ScaleY="1.5" />
<Style x:Key="ImageStyle" TargetType="Image">
<Style.Setters>
<Setter Property="Image.RenderTransform" Value="{StaticResource Scale}" />
</Style.Setters>
<Style.Triggers>
<EventTrigger RoutedEvent="Image.MouseEnter">
<BeginStoryboard>
<BeginStoryboard.Storyboard>
<Storyboard Duration="0:0:0.2">
<DoubleAnimation
Storyboard.Target="{DynamicResource Scale}"
Storyboard.TargetProperty="ScaleX"
To="1.5" />
<DoubleAnimation
Storyboard.Target="{DynamicResource Scale}"
Storyboard.TargetProperty="ScaleY"
To="1.5" />
</Storyboard>
</BeginStoryboard.Storyboard>
</BeginStoryboard>
</EventTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Image Grid.Row="2" Width="100" Height="100" Source="C:\WindowPhoneApp7_1.PNG" Style="{StaticResource ImageStyle}">

Problem animating a WPF button

I have a button, this is a unique button, and his style should çn't match the style of all the others. So when you pass your mouse over this button, it should change its image. But it is not working, Here is the code... I'm starting at WPF so if you can point me what am I doing wrong would be really appreciated
<Button Name="RemoveButton" ClickMode="Press" BorderThickness="0" Background="Transparent" Style="{StaticResource ButtonStyle1}">
<Button.Content>
<Grid>
<Image x:Name="CloseActive" x:FieldModifier="public" Height="12" VerticalAlignment="Center" Source="/HTFS.Atlas.Portfolio.PortfolioClient.WCF.Controls;component/Images/tab-close.png" Visibility="Hidden" />
<Image x:Name="CloseInactive" x:FieldModifier="public" Height="12" VerticalAlignment="Center" Source="/HTFS.Atlas.Portfolio.PortfolioClient.WCF.Controls;component/Images/tab-close-inactive.png" />
</Grid>
</Button.Content>
<Button.Resources>
<Storyboard x:Key="MouseOverAnimation">
<DoubleAnimation Storyboard.TargetName="CloseActive" Storyboard.TargetProperty="Opacity" From="0" To="1" Duration="0:0:0.5" />
<DoubleAnimation Storyboard.TargetName="CloseInactive" Storyboard.TargetProperty="Opacity" From="1" To="0" Duration="0:0:0.5" />
</Storyboard>
<Storyboard x:Key="MouseOutAnimation">
<DoubleAnimation Storyboard.TargetName="CloseInactive" Storyboard.TargetProperty="Opacity" From="0" To="1" Duration="0:0:0.5" />
<DoubleAnimation Storyboard.TargetName="CloseActive" Storyboard.TargetProperty="Opacity" From="1" To="0" Duration="0:0:0.5" />
</Storyboard>
<Style x:Key="CloseButtonStyle" TargetType="{x:Type Control}">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Trigger.EnterActions>
<BeginStoryboard Storyboard="{StaticResource MouseOverAnimation}" />
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard Storyboard="{StaticResource MouseOutAnimation}" />
</Trigger.ExitActions>
</Trigger>
</Style.Triggers>
</Style>
</Button.Resources>
</Button>
For the CloseActive image, instead of using Visibility="Hidden" try Opacity="0".
In your animation you're adjusting the opacity of the image, but it's still hidden.
In addition to removing the visibility attribute, try putting the animation triggers directly in Button.Triggers
<Button.Triggers>
<EventTrigger RoutedEvent="Button.MouseEnter">
<BeginStoryboard Storyboard="{StaticResource MouseOverAnimation}" />
</EventTrigger>
<EventTrigger RoutedEvent="Button.MouseLeave">
<BeginStoryboard Storyboard="{StaticResource MouseOutAnimation}" />
</EventTrigger>
</Button.Triggers>
since you can't use Storyboard.TargetName in a storyboard called from a style. You'll also have to use event triggers instead of normal triggers.
You can also remove the CloseButtonStyle since it won't be used.

Resources