I have a customized animated button with this style:
<Style TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<ControlTemplate.Resources>
<Storyboard x:Key="MenuBtnMouseEnterSb">
<DoubleAnimation Storyboard.TargetProperty="ScaleX" Storyboard.TargetName="btnScaleTransform"
To="0.92"
Duration="0:0:0.1">
<DoubleAnimation.EasingFunction>
<ExponentialEase Exponent="2" EasingMode="EaseInOut"></ExponentialEase>
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
<DoubleAnimation Storyboard.TargetProperty="ScaleY" Storyboard.TargetName="btnScaleTransform"
To="0.92"
Duration="0:0:0.1">
<DoubleAnimation.EasingFunction>
<ExponentialEase Exponent="2" EasingMode="EaseInOut"></ExponentialEase>
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
<Storyboard x:Key="MenuBtnMouseExitSb">
<DoubleAnimation Storyboard.TargetProperty="ScaleX" Storyboard.TargetName="btnScaleTransform"
To="1"
Duration="0:0:0.2">
<DoubleAnimation.EasingFunction>
<BounceEase Bounces="1" Bounciness="5"></BounceEase>
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
<DoubleAnimation Storyboard.TargetProperty="ScaleY" Storyboard.TargetName="btnScaleTransform"
To="1"
Duration="0:0:0.2">
<DoubleAnimation.EasingFunction>
<BounceEase Bounces="1" Bounciness="5" EasingMode="EaseInOut">
</BounceEase>
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
<Storyboard x:Key="MenuBtnMouseClickSb" AutoReverse="True">
<DoubleAnimation Storyboard.TargetProperty="ScaleX" Storyboard.TargetName="btnScaleTransform"
To="0.75"
Duration="0:0:0.2"></DoubleAnimation>
<DoubleAnimation Storyboard.TargetProperty="ScaleY" Storyboard.TargetName="btnScaleTransform"
To="0.75"
Duration="0:0:0.2"></DoubleAnimation>
</Storyboard>
</ControlTemplate.Resources>
<Border x:Name="border" BorderBrush="Transparent" CornerRadius="10" Background="{TemplateBinding Background}" Width="{TemplateBinding Width}"
Height="{TemplateBinding Height}" TextBlock.Foreground="{TemplateBinding Foreground}" Margin="{TemplateBinding Margin}" Padding="{TemplateBinding Padding}" RenderTransformOrigin="0.5, 0.5">
<ContentPresenter Margin="1"
HorizontalAlignment="Center"
VerticalAlignment="Center"
RecognizesAccessKey="True" />
<Border.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleX="1" ScaleY="1" x:Name="btnScaleTransform"></ScaleTransform>
</TransformGroup>
</Border.RenderTransform>
<Border.Triggers>
<EventTrigger RoutedEvent="Button.MouseEnter">
<BeginStoryboard Storyboard="{DynamicResource MenuBtnMouseEnterSb}" />
</EventTrigger>
<EventTrigger RoutedEvent="Button.MouseLeave">
<BeginStoryboard Storyboard="{DynamicResource MenuBtnMouseExitSb}" />
</EventTrigger>
<EventTrigger RoutedEvent="Button.PreviewMouseDown">
<BeginStoryboard Storyboard="{DynamicResource MenuBtnMouseClickSb}" />
</EventTrigger>
</Border.Triggers>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Basically, whenever mouse enters this button - button becomes smaller and when PreviewMouseDown event happens (when I press mouse button) it must become even more small. But what actually happens is that button returns to it's original size when I press a left button - i.e. MouseLeave event is fired and when I release left mouse button MouseEnter is fired again.
I added handlers for PreviewMouseDown and MouseLeave events and after PreviewMouseDown is handled - MouseLeave is handled immediately which I suppose is causing the MouseExit animation to run instead of MouseClick.
I've tested it again with Console.Writelines in each handler and it seems that MouseLeave handler is not called but animation still works as I described earlier.
I removed MouseLeave eventtrigger and now proper mousedown animation is running but it returns only to 0.92 scale (MouseEnter animation) and cannot return to original size when cursor is outside (that's what MouseLeave animation did).
The solution for my problem is simple: Use VisualStates instead of Triggers for such task.
I just copied my animations into VisualStates and they now work as I expected:
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal">
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="ScaleX" Storyboard.TargetName="btnScaleTransform"
To="1"
Duration="0:0:0.2">
<DoubleAnimation.EasingFunction>
<BounceEase Bounces="1" Bounciness="5"></BounceEase>
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
<DoubleAnimation Storyboard.TargetProperty="ScaleY" Storyboard.TargetName="btnScaleTransform"
To="1"
Duration="0:0:0.2">
<DoubleAnimation.EasingFunction>
<BounceEase Bounces="1" Bounciness="5" EasingMode="EaseInOut">
</BounceEase>
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
</VisualState>
<VisualState x:Name="MouseOver">
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="ScaleX" Storyboard.TargetName="btnScaleTransform"
To="0.92"
Duration="0:0:0.1">
<DoubleAnimation.EasingFunction>
<ExponentialEase Exponent="2" EasingMode="EaseInOut"></ExponentialEase>
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
<DoubleAnimation Storyboard.TargetProperty="ScaleY" Storyboard.TargetName="btnScaleTransform"
To="0.92"
Duration="0:0:0.1">
<DoubleAnimation.EasingFunction>
<ExponentialEase Exponent="2" EasingMode="EaseInOut"></ExponentialEase>
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
</VisualState>
<VisualState x:Name="Pressed">
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="ScaleX" Storyboard.TargetName="btnScaleTransform"
To="0.75"
Duration="0:0:0.2">
</DoubleAnimation>
<DoubleAnimation Storyboard.TargetProperty="ScaleY" Storyboard.TargetName="btnScaleTransform"
To="0.75"
Duration="0:0:0.2">
</DoubleAnimation>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
Although it is kind of weird how Trigger based animations work...
Related
I'm trying to create an animated checkbox in WPF, similar to this one.
This question is NOT a duplicate of this one, because there is no problem with the framerate of the animation.
The animations and the storyboards are already in place, and working properly, but for some rason, while the animation is playing, it looks like the whole thing is shaking, as demonstrated here. The effect is best seen on the right border of the box.
The following is the XAML source code of the custom checkbox. I don't think that there is a need to post the code behind, since it doesn't contain anything other than the RoutedEvent definitions (FlatCheckBox.Checked and FlatCheckBox.Unchecked).
<UserControl x:Name="userControl" x:Class="Sync_Launcher.Controls.FlatCheckBox"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:controls="clr-namespace:Sync_Launcher.Controls"
mc:Ignorable="d"
d:DesignHeight="30"
Background="Transparent" MouseLeftButtonDown="FlatCheckBox_OnMouseLeftButtonDown">
<Grid SnapsToDevicePixels="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{Binding ActualHeight, ElementName=userControl}"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid Column="0">
<Grid Name="tickHolderGridRoot" Margin="4">
<Grid.LayoutTransform>
<TransformGroup>
<RotateTransform x:Name="rotationTransform" Angle="0"/>
</TransformGroup>
</Grid.LayoutTransform>
<Grid Name="tickHolderGrid" Margin="0,0">
<Border Name="tickBorder" SnapsToDevicePixels="True" Opacity="0" BorderThickness="2,0,0,2" BorderBrush="#FF1CA36F" />
<Border Name="overlayBorder" SnapsToDevicePixels="True" Opacity="1" BorderThickness="2,2,2,2" BorderBrush="#FF404D61" />
</Grid>
</Grid>
</Grid>
<Label
Grid.Column="1"
Content="{Binding Text, ElementName=userControl}"
VerticalContentAlignment="Center"
FontSize="16"
Padding="5,0"
FontStyle="{Binding FontStyle, ElementName=userControl}"
FontWeight="{Binding FontWeight, ElementName=userControl}"/>
</Grid>
<UserControl.Resources>
<Duration x:Key="animationDuration">0:0:0.4</Duration>
<KeyTime x:Key="animationEnd">0:0:0.4</KeyTime>
</UserControl.Resources>
<UserControl.Triggers>
<EventTrigger SourceName="userControl" RoutedEvent="controls:FlatCheckBox.Checked">
<BeginStoryboard>
<Storyboard Timeline.DesiredFrameRate="60">
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="rotationTransform" Storyboard.TargetProperty="Angle" Duration="{StaticResource animationDuration}">
<EasingDoubleKeyFrame KeyTime="0" Value="0"/>
<EasingDoubleKeyFrame KeyTime="{StaticResource animationEnd}" Value="-60">
<EasingDoubleKeyFrame.EasingFunction>
<CircleEase EasingMode="EaseOut"/>
</EasingDoubleKeyFrame.EasingFunction>
</EasingDoubleKeyFrame>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimation Storyboard.TargetName="overlayBorder" Storyboard.TargetProperty="Opacity" From="1" To="0" Duration="{StaticResource animationDuration}"/>
<DoubleAnimation Storyboard.TargetName="tickBorder" Storyboard.TargetProperty="Opacity" From="0" To="1" Duration="{StaticResource animationDuration}"/>
<ThicknessAnimation Storyboard.TargetName="tickHolderGrid" Storyboard.TargetProperty="Margin" From="0,0" To="0,2" Duration="{StaticResource animationDuration}"/>
<ThicknessAnimation Storyboard.TargetName="tickHolderGridRoot" Storyboard.TargetProperty="Margin" From="4" To="2,0,2,4" Duration="{StaticResource animationDuration}"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger SourceName="userControl" RoutedEvent="controls:FlatCheckBox.Unchecked">
<BeginStoryboard>
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="rotationTransform" Storyboard.TargetProperty="Angle" Duration="{StaticResource animationDuration}">
<EasingDoubleKeyFrame KeyTime="0" Value="-60"/>
<EasingDoubleKeyFrame KeyTime="{StaticResource animationEnd}" Value="0">
<EasingDoubleKeyFrame.EasingFunction>
<CircleEase EasingMode="EaseOut"/>
</EasingDoubleKeyFrame.EasingFunction>
</EasingDoubleKeyFrame>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimation Storyboard.TargetName="overlayBorder" Storyboard.TargetProperty="Opacity" From="0" To="1" Duration="{StaticResource animationDuration}"/>
<DoubleAnimation Storyboard.TargetName="tickBorder" Storyboard.TargetProperty="Opacity" From="1" To="0" Duration="{StaticResource animationDuration}"/>
<ThicknessAnimation Storyboard.TargetName="tickHolderGrid" Storyboard.TargetProperty="Margin" From="0,2" To="0,0" Duration="{StaticResource animationDuration}"/>
<ThicknessAnimation Storyboard.TargetName="tickHolderGridRoot" Storyboard.TargetProperty="Margin" From="2" To="4" Duration="{StaticResource animationDuration}"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</UserControl.Triggers>
I have tried increasing the storyboard framerate by settings the Timeline.DesiredFrameRate to 60, as you can see in the code, but it had no effect on the shakyness of the animation.
I have also tried setting the SnapsToDevicePixels property to true hoping that it would improve the animation.
What might be the cause of this shaking effect, what can I do to eliminate it?
So I have a Path object that is implemented as follows:
<Path x:Name="arrow" Data="M0,0L0.67,0 4,2.67 7.25,0 8,0 8,0.67 4,4 0,0.75z" Fill="Black" Height="4" RenderTransformOrigin="0.5,0.5" Stretch="None" Width="8">
<Path.RenderTransform>
<TransformGroup>
<RotateTransform Angle="0"/>
<TranslateTransform/>
</TransformGroup>
</Path.RenderTransform>
</Path>
With this Path I have the following animation attached that works perfectly.
WORKING:
<VisualStateGroup x:Name="ExpandStateGroup">
<VisualState x:Name="Expanded">
<Storyboard>
<DoubleAnimation Duration="0:0:0.2" To="180" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(RotateTransform.Angle)" Storyboard.TargetName="arrow"/>
</Storyboard>
</VisualState>
<VisualState x:Name="Collapsed">
<Storyboard>
<DoubleAnimation Duration="0:0:0.2" To="0" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(RotateTransform.Angle)" Storyboard.TargetName="arrow"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
However when I add the color animations neither of the animations work. Also, the expand seems to happen instantaneously rather than expanding smoothly. The Collapse works fine though.
NOT WORKING:
<VisualStateGroup x:Name="ExpandStateGroup">
<VisualState x:Name="Expanded">
<Storyboard>
<ColorAnimation To="Red" Duration="0:0:0.2" Storyboard.TargetProperty="(Path.Fill).(SolidColorBrush.Color)" Storyboard.TargetName="arrow" />
<DoubleAnimation Duration="0:0:0.2" To="180" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(RotateTransform.Angle)" Storyboard.TargetName="arrow"/>
</Storyboard>
</VisualState>
<VisualState x:Name="Collapsed">
<Storyboard>
<ColorAnimation To="Black" Duration="0:0:0.2" Storyboard.TargetProperty="(Path.Fill).(SolidColorBrush.Color)" Storyboard.TargetName="arrow" />
<DoubleAnimation Duration="0:0:0.2" To="0" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(RotateTransform.Angle)" Storyboard.TargetName="arrow"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
It has to do with the coloranimation because when I try to perform the color animation by itself it doesn't work.
This is a part of the Telerik RadExpander user control.
If any other information is needed please don't hesitate to ask.
NOTE 1:
If I set the Fill color in the path declaration to black and set the collapsed fill color to green the arrow will start out as green, but as soon as I expand it turns black and never changes color again.
Note 2: When the coloranimation is set the doubleanimation never works.
How can I access the "image" from code behind in order to change its image source?
xaml code looks like this
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
x:Class="Demo.ChartButton"
d:DesignWidth="100" d:DesignHeight="100">
<UserControl.Resources>
<Style x:Key="ButtonStyle1" TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal"/>
<VisualState x:Name="MouseOver">
<Storyboard>
<ColorAnimation Duration="0" To="White" Storyboard.TargetProperty="(UIElement.Effect).(DropShadowEffect.Color)" Storyboard.TargetName="image" d:IsOptimized="True" />
<DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="(UIElement.Effect).(DropShadowEffect.ShadowDepth)" Storyboard.TargetName="image" d:IsOptimized="True"/>
<DoubleAnimation Duration="0" To="5" Storyboard.TargetProperty="(UIElement.Effect).(DropShadowEffect.BlurRadius)" Storyboard.TargetName="image" d:IsOptimized="True"/>
<DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="(UIElement.Effect).(DropShadowEffect.Opacity)" Storyboard.TargetName="image" d:IsOptimized="True"/>
</Storyboard>
</VisualState>
<VisualState x:Name="Pressed">
<Storyboard>
<ColorAnimation Duration="0" To="AntiqueWhite" Storyboard.TargetProperty="(UIElement.Effect).(DropShadowEffect.Color)" Storyboard.TargetName="image" d:IsOptimized="True"/>
<DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="(UIElement.Effect).(DropShadowEffect.Opacity)" Storyboard.TargetName="image" d:IsOptimized="True"/>
</Storyboard>
</VisualState>
<VisualState x:Name="Disabled">
<Storyboard>
<DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="(UIElement.Effect).(DropShadowEffect.Opacity)" Storyboard.TargetName="image" d:IsOptimized="True"/>
<ColorAnimation Duration="0" To="#FFAFAFAF" Storyboard.TargetProperty="(UIElement.Effect).(DropShadowEffect.Color)" Storyboard.TargetName="image" d:IsOptimized="True"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Image x:Name="image" RenderTransformOrigin="0,0" Source="/Demo;component/spreadsheet-icon.png" >
<Image.Effect>
<DropShadowEffect ShadowDepth="0" BlurRadius="10" Color="Black" Opacity="1"/>
</Image.Effect>
</Image>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
<Button Content="" Margin="0,0,0,0" Style="{StaticResource ButtonStyle1}" Click="Button_Click" />
Any help is appreciated.
The only way to access this is to navigate the visual tree to locate the image. Using Linq-To-VisualTree, you can locate it as follows:
using LinqToVisualTree
private void Button_Click(object sender, EventArgs e)
{
Button button = sender as Button;
Image img = button.Descendants<Image>().Single() as Image;
img.Source = "..."
}
I am trying to create a Silverlight Toggle button style that would flip between a plus and a minus sign. Unfortunately it is always showing a minus sign. Can anyone tell me what's the problem with this style:
<Style x:Key="PlusMinusToggleButtonStyle" TargetType="ToggleButton">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
<Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CheckStates">
<VisualState x:Name="Unchecked">
<Storyboard>
<DoubleAnimation Storyboard.TargetName="UncheckedVisual" Storyboard.TargetProperty="Opacity" To="0" Duration="1" />
<DoubleAnimation Storyboard.TargetName="CheckedVisual" Storyboard.TargetProperty="Opacity" To="1" Duration="0" />
</Storyboard>
</VisualState>
<VisualState x:Name="Checked">
<Storyboard>
<DoubleAnimation Storyboard.TargetName="UncheckedVisual" Storyboard.TargetProperty="Opacity" To="1" Duration="0" />
<DoubleAnimation Storyboard.TargetName="CheckedVisual" Storyboard.TargetProperty="Opacity" To="0" Duration="1" />
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Grid>
<Image x:Name="UncheckedVisual" Source="plus.png" Stretch="None" />
<Image x:Name="CheckedVisual" Source="minus.png" Stretch="None" />
</Grid>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
You need to expand on the DoubleAnimation, put in KeyFrame Animation in it. Also set the base opacity to 0 and then fade in the respective one you need. For example:
<VisualState x:Name="Checked">
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="CheckedVisual" Storyboard.TargetProperty="Opacity">
<EasingDoubleKeyFrame KeyTime="0" Value="0"/>
<EasingDoubleKeyFrame KeyTime="0:0:1" Value="1"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
Everytime a state is changed, it goes back to the base state then to the state that was called. Because a togglebutton is always in an on or off state, it will not be in an invisible state.
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.