Smooth transition from image to image - wpf

Here is my XAML:
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Image x:Name="Expander_Normal"
Source="/Images/arrow-e.tiff" Width="13" Height="13" />
<ControlTemplate.Triggers>
<Trigger Property="ToggleButton.IsChecked" Value="True">
<Setter x:Name="Expander_Expanded"
TargetName="Expander_Normal" Property="Source"
Value="/Images/arrow-s.tiff" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
The transition from image to another image is very rough and I don't really like it. So how can I make the transitions smooth.
UPDATE:
Maybe instead of changing the image, maybe ROTATE the image. The main image looks like >. So maybe rotate it down (90 degrees clockwise)

If you want to go fancy, you could:
Add a story board
Use a double animation on opacity to fade out the image box
Change the image
Use another double animation to fade in the image box
UPDATE
To rotate the image:
Add a rotate transform to the image
Use a double animation on the rotate transform's angle property
See http://www.vbforums.com/showthread.php?t=555120 for an example

Try this:
<Grid>
<Image Source="Image1.png"
Height="100" Width="100">
<Image.Triggers>
<EventTrigger RoutedEvent="MouseEnter">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
BeginTime="0:0:0"
Duration="0:0:0.5"
From="1"
To="0"
Storyboard.TargetProperty="(Image.Opacity)"
/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="MouseLeave">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
BeginTime="0:0:0"
Duration="0:0:0.8"
From="0"
To="1"
Storyboard.TargetProperty="(Image.Opacity)"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Image.Triggers>
</Image>
<Image Source="Image2.png"
Height="100" Width="100" Opacity="0">
<Image.Triggers>
<EventTrigger RoutedEvent="MouseEnter">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
BeginTime="0:0:0"
Duration="0:0:0.5"
From="0"
To="1"
Storyboard.TargetProperty="(Image.Opacity)"
/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="MouseLeave">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
BeginTime="0:0:0"
Duration="0:0:0.8"
From="1"
To="0"
Storyboard.TargetProperty="(Image.Opacity)"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Image.Triggers>
</Image>
</Grid>

Related

Style.Trigger vs. Grid.Trigger

In my Code I have defined two Triggers, a Label and a Canvas.
The description of my problem:
When the cursor goes straight across the Label, the Style.Trigger gets activated and the background colour changes (to orange). When the cursor runs across the canvas-area the Grid.Trigger gets activated and changes the background color(to violet). So far, so good.Is the cursor now, running (after the Grid.Trigger was active) across the label-area the background does not change at all.
It seems to me that the Grid.Trigger gets priority once it was active.
<Window x:Class="Sample01.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.Resources>
<!-- Defined Style starts here -->
<Style x:Key="{x:Type Label}" TargetType="{x:Type Label}" >
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Trigger.Setters>
</Trigger.Setters>
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation To="DarkOrange" Duration="0:0:0.5"
Storyboard.TargetProperty="Background.Color"
/>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation To="White" Duration="0:0:1"
Storyboard.TargetProperty="Background.Color" />
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
</Style.Triggers>
</Style>
<!-- End defined Style-->
</Grid.Resources>
<!-- Define Trigger -->
<Grid.Triggers>
<EventTrigger RoutedEvent="MouseEnter"
SourceName="canvas">
<BeginStoryboard>
<Storyboard>
<ColorAnimation To="BlueViolet" Duration="0:0:1"
Storyboard.TargetProperty="Background.Color"
Storyboard.TargetName="label" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="MouseLeave"
SourceName="canvas">
<BeginStoryboard>
<Storyboard>
<ColorAnimation To="White" Duration="0:0:1"
Storyboard.TargetProperty="Background.Color"
Storyboard.TargetName="label" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Grid.Triggers>
<Label x:Name="label" VerticalAlignment="Top" Height="100" BorderBrush="Black" BorderThickness="2" Content="LABEL"/>
<Canvas x:Name="canvas" Height="100" VerticalAlignment="Bottom"
IsHitTestVisible="True"
Background="AntiqueWhite"
/>
</Grid>
Can someone explain this behavior ?
You're running into the order of precedence of value sources for Dependency Properties. A common case of this is when you set a local value directly on an element, a value set in a style is overridden. In this case, you're applying an animation to the property, which takes precedence over anything set in the Style (or even a local value).
To allow the Style to take over again you need to make the animation no longer apply to the Label. You can do this by explicitly removing the initial animation, which will reset back to the original state, like a Property Trigger does:
<EventTrigger RoutedEvent="FrameworkElement.MouseEnter"
SourceName="canvas">
<BeginStoryboard x:Name="GridMouseover">
<Storyboard>
<ColorAnimation To="BlueViolet" Duration="0:0:1"
Storyboard.TargetProperty="Background.Color"
Storyboard.TargetName="label" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="FrameworkElement.MouseLeave"
SourceName="canvas">
<RemoveStoryboard BeginStoryboardName="GridMouseover"/>
</EventTrigger>
The disadvantage of this is that you lose the smooth animation back to White. VisualStateManager is a much better choice for this kind of thing in many cases because it handles that for you automatically.
The other thing you can do is tell the Storyboard to stop applying itself after finishing by changing the FillBehavior:
<EventTrigger RoutedEvent="FrameworkElement.MouseEnter"
SourceName="canvas">
<BeginStoryboard>
<Storyboard>
<ColorAnimation To="BlueViolet" Duration="0:0:1"
Storyboard.TargetProperty="Background.Color"
Storyboard.TargetName="label" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="FrameworkElement.MouseLeave"
SourceName="canvas">
<BeginStoryboard>
<Storyboard FillBehavior="Stop">
<ColorAnimation To="White" Duration="0:0:1"
Storyboard.TargetProperty="Background.Color"
Storyboard.TargetName="label" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>

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>

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.

WPF DoubleAnimation does not decrease the value after an animation

Consider the following simple WPF form, we will try to animate border1's Height:
This is the XAML for border1:
<Border Margin="3" BorderBrush="Black" BorderThickness="1" Name="border1">
<Border.Style>
<Style>
<Setter Property="Control.Height" Value="50" />
<Style.Triggers>
<DataTrigger Binding="{Binding X}" Value="1">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Duration="0:0:0.2" Storyboard.TargetProperty="Height" To="100" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
<DataTrigger Binding="{Binding X}" Value="2">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Duration="0:0:0.2" Storyboard.TargetProperty="Height" To="200" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
<DataTrigger Binding="{Binding X}" Value="3">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Duration="0:0:0.2" Storyboard.TargetProperty="Height" To="300" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
<TextBlock Text="{Binding X}" />
</Border>
X is a normal DependencyProperty and buttons do their work without problem and TextBlock's content inside border1 shows the changed value.
Now the problem is Height can be only Increased! For example by pressing 1, Height increases to 100, pressing 3 increases it to 300 but pressing 2 does not change the height.
If I set the initial border1's height to, for example, 400, all buttons can decrease it to 100, 200 or 300 but after this stage no animation can decrease border's height.
Am I missing some obvious point regarding WPF animation?
Update
Part of the issue is the storyboard in the DataTrigger is not being stopped, so (the last DataTrigger defined) is always holding the Height's 'animated' value.
Adding a StopStoryboard in the exit action fixes part of it. You can now switch between all three heights again... but the animation always starts from the Height's base value (which is clearly not what you want). You want it to start from where it was last set at.
The following MSDN article explains the second issue pretty well:
http://msdn.microsoft.com/en-us/library/aa970493.aspx
Good Solution- EventTriggers on your three buttons seem to work better and doesn't have the problems that the DataTrigger encounters (plus you don't even need the dependency property 'X' anymore!)
<Border Margin="3" BorderBrush="Black" BorderThickness="1" Name="border1">
<Border.Style>
<Style>
<Setter Property="Control.Height" Value="50" />
</Style>
</Border.Style>
<TextBlock Text="{Binding X}" />
</Border>
and
<StackPanel Orientation="Horizontal">
<Button Content="1" Width="50">
<Button.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Duration="0:0:0.2" Storyboard.TargetName="border1" Storyboard.TargetProperty="Height" To="100"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Button.Triggers>
</Button>
<Button Content="2" Width="50">
<Button.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Duration="0:0:0.2" Storyboard.TargetName="border1" Storyboard.TargetProperty="Height" To="200"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Button.Triggers>
</Button>
<Button Content="3" Width="50">
<Button.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Duration="0:0:0.2" Storyboard.TargetName="border1" Storyboard.TargetProperty="Height" To="300"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Button.Triggers>
</Button>
</StackPanel>
There must be a simpler way to do this, but I cannot recall if there is at the moment.
Otherwise this will work. You can set the ExitAction of your triggers to set back to the default value. Do this by using a DoubleAnimation with no To value.
i.e.,
<DataTrigger Binding="{Binding X}" Value="1">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Height" Duration="0:0:0.2" To="100" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Height" Duration="0:0:0.2" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.ExitActions>
</DataTrigger>

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