WPF Rectangle Triggers when Visible for DoubleAnimation StoryBoard - wpf

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>

Related

Image Animation with a Button WPF

I have an image within a button, I've wrote an animation that leads to Grow or Shrink When IsMouseOver Occurs, However I dont want the button itself Grows or Shrinks but the Image within the Button has to Grow or Shrink. Do you have any idea? I am all yours.
here is my .XAML
<Button Margin="355,0,0,0" Width="100" Height="300" Click="Button_Click_1">
<Image Source="img/blue.jpg" />
<Button.Style>
<Style TargetType="Button">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ThicknessAnimation Duration="0:0:0.250" To="0"
Storyboard.TargetProperty="BorderThickness" />
<DoubleAnimation Duration="0:0:0.350" To="320"
Storyboard.TargetProperty="Height" />
<DoubleAnimation Duration="0:0:0.350" To="120"
Storyboard.TargetProperty="Width" />
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<ThicknessAnimation Duration="0:0:0.250" To="0"
Storyboard.TargetProperty="BorderThickness" />
<DoubleAnimation Duration="0:0:0.550" To="300"
Storyboard.TargetProperty="Height" />
<DoubleAnimation Duration="0:0:0.550" To="100"
Storyboard.TargetProperty="Width" />
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
You can simply apply the Style to the Image instead of the Button.
<Button ...>
<Image ...>
<Image.Style>
<Style TargetType="Image">
<Style.Triggers>
<!-- You get the idea -->
Note that Image does not have a Border control, therefore you can't use the BorderThickness animation on the Image, you can instead apply this animation on the Button as you were doing before.
Also, your Image will require a Height in order to animate. Otherwise, you can use the From property on the DoubleAnimation like this:
<DoubleAnimation Duration="0:0:0.350" From="300" To="320"
Storyboard.TargetProperty="Height" />
You have to give Height and Width to Image, else will get an Exception. As Mike said can't use BorderThickness.
<Button>
<Image Source="Edit.png" Height="50" Width="50">
<Image.Style>
<Style TargetType="Image">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<!--<ThicknessAnimation Duration="0:0:0.250" To="0" Storyboard.TargetProperty="BorderThickness" />-->
<DoubleAnimation Duration="0:0:0.350" To="320" Storyboard.TargetProperty="Height" />
<DoubleAnimation Duration="0:0:0.350" To="120" Storyboard.TargetProperty="Width" />
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<!--<ThicknessAnimation Duration="0:0:0.250" To="0" Storyboard.TargetProperty="BorderThickness" />-->
<DoubleAnimation Duration="0:0:0.550" To="300" Storyboard.TargetProperty="Height" />
<DoubleAnimation Duration="0:0:0.550" To="100" Storyboard.TargetProperty="Width" />
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
</Button>
Or you could try this
<Button Margin="355,0,0,0" Width="100" Height="300" Click="Button_Click_1">
<Border Width="50" Height="150">
<Border.Style>
<Style TargetType="Border">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ThicknessAnimation Duration="0:0:0.250" To="0"
Storyboard.TargetProperty="BorderThickness" />
<DoubleAnimation Duration="0:0:0.350" To="320"
Storyboard.TargetProperty="Height" />
<DoubleAnimation Duration="0:0:0.350" To="120"
Storyboard.TargetProperty="Width" />
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<ThicknessAnimation Duration="0:0:0.250" To="0"
Storyboard.TargetProperty="BorderThickness" />
<DoubleAnimation Duration="0:0:0.550" To="150"
Storyboard.TargetProperty="Height" />
<DoubleAnimation Duration="0:0:0.550" To="50"
Storyboard.TargetProperty="Width" />
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
</Style.Triggers>
</Style>
</Border.Style>
<Image Source="MyImage.jpg" Stretch="UniformToFill"/>
</Border>
</Button>

Expander collapse animation not work

I have implement some animation on Expander.Expanded and this work fine, but similar one does not work on Expander.Collapsed.
XAML:
<Border Name="bor3" >
<Border.Triggers>
<EventTrigger RoutedEvent="Expander.Expanded" SourceName="exp3">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
From="0"
To="1"
Duration="0:0:0.25"
Storyboard.TargetName="gr3"
Storyboard.TargetProperty="(FrameworkElement.LayoutTransform).(ScaleTransform.ScaleY)"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
<EventTrigger RoutedEvent="Expander.Collapsed" SourceName="exp3" >
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
From="1"
To="0"
Duration="0:0:0.25"
Storyboard.TargetName="gr3"
Storyboard.TargetProperty="(FrameworkElement.LayoutTransform).(ScaleTransform.ScaleY)"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Border.Triggers>
<Expander Name="exp3">
<Grid Name="gr3">
<Grid.LayoutTransform>
<ScaleTransform ScaleX="1" ScaleY="0"/>
</Grid.LayoutTransform>
<TextBlock >Test!</TextBlock>
</Grid>
</Expander>
</Border>
UPDATE:
I've test Datatriggers beside control Style but that has a same problem:
<Border Name="bor3" >
<Expander Name="exp3">
<Grid Name="gr3">
<Grid.Style>
<Style TargetType="Grid">
<Style.Triggers>
<DataTrigger Binding="{Binding IsExpanded, RelativeSource={RelativeSource AncestorType=Expander}}" Value="true">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
From="0"
To="1"
Duration="0:0:0.25"
Storyboard.TargetProperty="(FrameworkElement.LayoutTransform).(ScaleTransform.ScaleY)"/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
From="1"
To="0"
Duration="0:0:0.25"
Storyboard.TargetProperty="(FrameworkElement.LayoutTransform).(ScaleTransform.ScaleY)"/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Grid.Style>
<Grid.LayoutTransform>
<ScaleTransform ScaleX="1" ScaleY="0"/>
</Grid.LayoutTransform>
<TextBlock >Test!</TextBlock>
</Grid>
</Expander>
</Border>
What is the problem and What is the solution?!
Before the collapse animation played his parent (ExpandSite ContentPresenter) becomes invisible. so we must make it visible before the collapse animation played:
XAML:
<Border Name="bor3" VerticalAlignment="Top" >
<Expander Name="exp3" Collapsed="exp3_Collapsed" >
<Expander.Resources>
<Storyboard x:Key="sbCollapse" >
<DoubleAnimation Storyboard.TargetName="gr3"
From="1"
To="0"
Duration="0:0:0.5"
Storyboard.TargetProperty="(FrameworkElement.LayoutTransform).(ScaleTransform.ScaleY)"/>
</Storyboard>
<Storyboard x:Key="sbExpand" >
<DoubleAnimation Storyboard.TargetName="gr3"
From="0"
To="1"
Duration="0:0:0.5"
Storyboard.TargetProperty="(FrameworkElement.LayoutTransform).(ScaleTransform.ScaleY)"/>
</Storyboard>
</Expander.Resources>
<Expander.Triggers>
<EventTrigger RoutedEvent="Expander.Expanded">
<BeginStoryboard Storyboard="{StaticResource sbExpand}" />
</EventTrigger>
</Expander.Triggers>
<Grid Name="gr3" Background="Green" Height="100">
<Grid.LayoutTransform>
<ScaleTransform ScaleX="1" ScaleY="0"/>
</Grid.LayoutTransform>
<TextBlock FontSize="40">Test!</TextBlock>
</Grid>
</Expander>
</Border>
Code:
private void exp3_Collapsed(object sender, RoutedEventArgs e)
{
var r = exp3.Template.FindName("ExpandSite", exp3) as UIElement;
r.Visibility = System.Windows.Visibility.Visible;
var sb1 = (Storyboard)exp3.FindResource("sbCollapse");
sb1.Begin();
}
;)

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>

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}">

How do you keep an item at the same point on a Canvas in XAML as it grows or shrinks in size?

I have the following xaml that illustrates a circle that grows and shrinks in size. I want my center point of my circle to stay put on my canvas as the animation runs.
<Window.Triggers>
<EventTrigger RoutedEvent="Window.Loaded">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation RepeatBehavior="Forever" AutoReverse="True" From="10" To="360" Duration="0:0:3" Storyboard.TargetName="GrowMe" Storyboard.TargetProperty="Width"/>
<DoubleAnimation RepeatBehavior="Forever" AutoReverse="True" From="10" To="360" Duration="0:0:3" Storyboard.TargetName="GrowMe" Storyboard.TargetProperty="Height"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Window.Triggers>
<Canvas Width="640" Height="480">
<Ellipse Width="10" Height="10" Stroke="Red" Canvas.Left="80" Canvas.Top="31"/>
<Ellipse x:Name="GrowMe" Width="10" Height="10" Stroke="Cyan" Canvas.Left="205" Canvas.Top="203"/>
Here is an example of a button that does exactly this. Note the RenderTransformOrigin property.
<Button RenderTransformOrigin="0.5,0.5" Command="{Binding ClickCommand}" Cursor="Hand">
<Button.RenderTransform>
<ScaleTransform ScaleX="1" ScaleY="1" />
</Button.RenderTransform>
<Button.Template>
<ControlTemplate>
<Label>
<Label.Background>
<VisualBrush Visual="{Binding Path=Shape, Converter={StaticResource myTestConv}}" />
</Label.Background>
</Label>
</ControlTemplate>
</Button.Template>
<Button.Style>
<Style TargetType="Button">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="RenderTransform.ScaleX"
To="1.3" Duration="0:0:0.1" AccelerationRatio="0.5"/>
<DoubleAnimation Storyboard.TargetProperty="RenderTransform.ScaleY"
To="1.3" Duration="0:0:0.1" AccelerationRatio="0.5"/>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="RenderTransform.ScaleX"
To="1" Duration="0:0:0.5"/>
<DoubleAnimation Storyboard.TargetProperty="RenderTransform.ScaleY"
To="1" Duration="0:0:0.5"/>
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>
<local:TooltipServiceEx.ToolTipEx>
<local:ToolTipEx
HideToolTipTimeout="{StaticResource TooltipTimeout}" />
</local:TooltipServiceEx.ToolTipEx>
<ToolTipService.ToolTip>
<ToolTip
Template="{StaticResource EventTooltipStyle}" />
</ToolTipService.ToolTip>
</Button>
You can do it easily animating ScaleTransform inside RenderTransform and set RenderTransformOrigin = "0.5, 0.5".
--EDIT--
Then your change your storyboard to following:
<Storyboard>
<DoubleAnimation RepeatBehavior="Forever" AutoReverse="True" From="10" To="180" Duration="0:0:3" Storyboard.TargetName="GrowMe" Storyboard.TargetProperty="Width"/>
<DoubleAnimation RepeatBehavior="Forever" AutoReverse="True" From="10" To="180" Duration="0:0:3" Storyboard.TargetName="GrowMe" Storyboard.TargetProperty="Height"/>
<DoubleAnimation RepeatBehavior="Forever" AutoReverse="True" By="-180" Duration="0:0:3" Storyboard.TargetName="GrowMe" Storyboard.TargetProperty="(Canvas.Left)"/>
<DoubleAnimation RepeatBehavior="Forever" AutoReverse="True" By="-180" Duration="0:0:3" Storyboard.TargetName="GrowMe" Storyboard.TargetProperty="(Canvas.Top)"/>
</Storyboard>
You need to devide your growth into half and add it to Width/Height and subtract it from Left/Top.

Resources