Style triggers don't inherit? - wpf

I have a style with the following triggers defined:
<Style TargetType="{x:Type graphicElements:MyTabItem}" x:Key="StMyTabItemBase">
<Setter Property="Foreground" Value="Black"/>
<Setter Property="SelectedColor" Value="{Binding ApplicationColor, RelativeSource={RelativeSource AncestorType=graphicElements:MyTabControl}}" />
<Setter Property="Expanded" Value="False" />
<Setter Property="BorderBrush" Value="#FFACACAC"/>
<Setter Property="Margin" Value="0"/>
<Setter Property="Padding" Value="0"/>
<Setter Property="HorizontalContentAlignment" Value="Left"/>
<Setter Property="VerticalContentAlignment" Value="Top"/>
<Setter Property="SnapsToDevicePixels" Value="False" />
<Setter Property="Template" Value="{StaticResource CtTabCollapsed}" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsSideBarExpanded, RelativeSource={RelativeSource AncestorType=graphicElements:MyTabControl}}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<BooleanAnimationUsingKeyFrames Storyboard.TargetProperty="Expanded" BeginTime="0" Duration="0">
<DiscreteBooleanKeyFrame Value="True" />
</BooleanAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<BooleanAnimationUsingKeyFrames Storyboard.TargetProperty="Expanded" BeginTime="0:0:0.25" Duration="0">
<DiscreteBooleanKeyFrame Value="False" />
</BooleanAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</DataTrigger.ExitActions>
</DataTrigger>
<Trigger Property="Expanded" Value="True">
<Setter Property="Template" Value="{StaticResource CtTabExpanded}" />
</Trigger>
</Style.Triggers>
</Style>
This works perfectly when I apply the direct style. However, I want to be able to create styles based on this style to override specific properties like margins and colors. I have tried to do so as follows (this creates a default based on this style):
<Style TargetType="{x:Type graphicElements:MyTabItem}" BasedOn="{StaticResource StMyTabItemBase}" />
However, as soon as I do that it no longer triggers or switches the template properly. If I copy just the triggers into the new style it works again, but I don't want to have to put the triggers into each style individually... Why aren't these inheriting like they are supposed to? Or do I misunderstand something about BasedOn and Triggers?
EDIT
Here is the 'BasedOn' style that works:
<Style TargetType="{x:Type graphicElements:AutodeskTabItem}" BasedOn="{StaticResource StAutodeskTabItemBase}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsSideBarExpanded, RelativeSource={RelativeSource AncestorType=graphicElements:AutodeskTabControl}}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<BooleanAnimationUsingKeyFrames Storyboard.TargetProperty="Expanded" BeginTime="0" Duration="0">
<DiscreteBooleanKeyFrame Value="True" />
</BooleanAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<BooleanAnimationUsingKeyFrames Storyboard.TargetProperty="Expanded" BeginTime="0:0:0.25" Duration="0">
<DiscreteBooleanKeyFrame Value="False" />
</BooleanAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</DataTrigger.ExitActions>
</DataTrigger>
<Trigger Property="Expanded" Value="True">
<Setter Property="Template" Value="{StaticResource CtTabExpanded}" />
</Trigger>
</Style.Triggers>
</Style>
Basically I just copied out the triggers portion of the base style. However I don't understand why I have to do that...

I'm not sure about "supposed to" but your exit storyboard definitely won't find the first.
I recently came across this behaviour. It's an oddity to do with namescope. That won't work.
You could try starting another storyboard targeting the same property with 0 duration and hope that stops it. This did not work in my case.
The way I work round this in my app is to use a multiconverter to start and stop the storyboard.
My converter:
public class MultiAnimatorConverter : MarkupExtension, IMultiValueConverter
{
public Storyboard sb { get; set; }
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
// 0 = Shape
// 1 = Tag
Shape shape = values[0] as Shape;
if(shape.Tag.ToString() == "False")
{
sb.Stop(shape);
sb.Remove(shape);
}
else
{
sb.Begin(shape, true);
}
return true; // Abusing isenabled so I don't need another attached dependency property
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
return null;
}
public override object ProvideValue(IServiceProvider serviceProvider)
{
return this;
}
}
You may prefer an attached property to enabled.
Useage:
<Setter Property="IsEnabled">
<Setter.Value>
<MultiBinding Converter="{ui:MultiAnimatorConverter sb={StaticResource MarchinAntsAnimation}}">
<Binding RelativeSource="{RelativeSource Self}"/>
<Binding Path="Tag" RelativeSource="{RelativeSource Self}"/>
</MultiBinding>
</Setter.Value>
</Setter>
My storyboard is a separate resource.
Storyboard.TargetProperty="(Shape.StrokeDashOffset)"
RepeatBehavior="Forever"
From="0"
To="8"
Duration="00:00:.8"
Timeline.DesiredFrameRate="10"
/>
This is used in my Map Editor ( for our game ). The user is drawing the map for a scenario. They draw terrain. Woods, rivers, contours etc. All are polygons with different templates and I use basedon to inherit so all would get the same "marching ants" animation with dotted lines animated round them when the terrain is selected for editing.

Related

WPF: Hiding object causes brief flash before disappearing

I have a simple button style which has data trigger which binds to a bool property and if property is false it hides the button using simple fade out animation and vice-versa.
But for some unknown reason, for the first time when I perform some task which sets the bool value to false. It gives a brief flash before fading out. Upon setting it to true everything is as expected.
My style is
<Style x:Key="CustomButtonStyle" TargetType="{x:Type Button}" >
<Style.Triggers>
<DataTrigger Binding="{Binding IsButtonVisible}" Value="true">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard Storyboard.TargetProperty="Opacity" >
<DoubleAnimation Duration="0:0:0.2" To="1"/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<BeginStoryboard>
<Storyboard Storyboard.TargetProperty="Opacity" >
<DoubleAnimation Duration="0:0:0.2" To="0"/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.ExitActions>
</DataTrigger>
<Trigger Property="Opacity" Value="0">
<Setter Property="Visibility" Value="Collapsed"></Setter>
</Trigger>
<Trigger Property="Opacity" Value="1" >
<Setter Property="Visibility" Value="Visible"></Setter>
</Trigger>
</Style.Triggers>
<Style.Setters>
<Setter Property="Height" Value="93"/>
<Setter Property="Width" Value="93"/>
<Setter Property="Opacity" Value="0"/>
</Style.Setters>
</Style>
Note:-
Default value of IsButtonVisible is true
Why do you have two DataTrigger? Try this solution, maybe it solves your problem.
<Style x:Key="DefaultButtonStyle" TargetType="{x:Type Button}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsVisible}" Value="true">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard FillBehavior="HoldEnd" Storyboard.TargetProperty="Opacity">
<DoubleAnimation Duration="0:0:0.2" To="1"/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<BeginStoryboard>
<Storyboard Storyboard.TargetProperty="Opacity" >
<DoubleAnimation Duration="0:0:0.2" To="0" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.ExitActions>
</DataTrigger>
<Trigger Property="Opacity" Value="0">
<Setter Property="Visibility" Value="Collapsed"></Setter>
</Trigger>
<Trigger Property="Opacity" Value="1">
<Setter Property="Visibility" Value="Visible"></Setter>
</Trigger>
</Style.Triggers>
<Style.Setters>
<Setter Property="Height" Value="93"/>
<Setter Property="Width" Value="93"/>
<Setter Property="Opacity" Value="0"/>
</Style.Setters>
</Style>
Edit:
XAML
<Window x:Class="WpfApplication1.MainWindow"
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"
xmlns:local="clr-namespace:WpfApplication1"
mc:Ignorable="d"
Title="MainWindow" Height="279.716" Width="279.784"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Window.Resources>
<Style x:Key="ButtonStyleTrue" TargetType="{x:Type Button}">
<Style.Triggers>
<DataTrigger Binding="{Binding VisibleTrue}" Value="true">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard FillBehavior="HoldEnd" Storyboard.TargetProperty="Opacity">
<DoubleAnimation Duration="0:0:0.2" To="1"/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<BeginStoryboard>
<Storyboard Storyboard.TargetProperty="Opacity" >
<DoubleAnimation Duration="0:0:0.2" To="0" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.ExitActions>
</DataTrigger>
<Trigger Property="Opacity" Value="0">
<Setter Property="Visibility" Value="Collapsed"></Setter>
</Trigger>
<Trigger Property="Opacity" Value="1">
<Setter Property="Visibility" Value="Visible"></Setter>
</Trigger>
</Style.Triggers>
<Style.Setters>
<Setter Property="Height" Value="93"/>
<Setter Property="Width" Value="93"/>
<Setter Property="Opacity" Value="0"/>
</Style.Setters>
</Style>
<Style x:Key="ButtonStyleFalse" TargetType="{x:Type Button}">
<Style.Triggers>
<DataTrigger Binding="{Binding VisibleFalse}" Value="true">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard FillBehavior="HoldEnd" Storyboard.TargetProperty="Opacity">
<DoubleAnimation Duration="0:0:0.2" To="1"/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<BeginStoryboard>
<Storyboard Storyboard.TargetProperty="Opacity" >
<DoubleAnimation Duration="0:0:0.2" To="0" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.ExitActions>
</DataTrigger>
<Trigger Property="Opacity" Value="0">
<Setter Property="Visibility" Value="Collapsed"></Setter>
</Trigger>
<Trigger Property="Opacity" Value="1">
<Setter Property="Visibility" Value="Visible"></Setter>
</Trigger>
</Style.Triggers>
<Style.Setters>
<Setter Property="Height" Value="93"/>
<Setter Property="Width" Value="93"/>
<Setter Property="Opacity" Value="0"/>
</Style.Setters>
</Style>
</Window.Resources>
<Grid>
<Button Content="Button" HorizontalAlignment="Left" Margin="187,11,0,0" VerticalAlignment="Top" Width="75" Click="Button_OnClick"/>
<Button Style="{StaticResource ButtonStyleFalse}" Content="Button" HorizontalAlignment="Left" Margin="47,66,0,0" VerticalAlignment="Top" Width="75"/>
<TextBlock x:Name="textBlock_true" HorizontalAlignment="Left" Margin="193,68,0,0" TextWrapping="Wrap" Text="TextBlock" VerticalAlignment="Top"/>
<Button Style="{StaticResource ButtonStyleTrue}" Content="Button" HorizontalAlignment="Left" Margin="47,143,0,0" VerticalAlignment="Top" Width="75"/>
<TextBlock x:Name="textBlock_false" HorizontalAlignment="Left" Margin="193,145,0,0" TextWrapping="Wrap" Text="TextBlock" VerticalAlignment="Top"/>
</Grid>
Code Behind
using System.ComponentModel;
using System.Windows;
namespace WpfApplication1
{
public partial class MainWindow : Window, INotifyPropertyChanged
{
/// <summary>
/// Initalvalue is true;
/// </summary>
public bool VisibleTrue
{
get { return _VisibleTrue; }
set
{
if (_VisibleTrue == value) return;
_VisibleTrue = value;
textBlock_true.Text = value ? "True" : "False";
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("VisibleTrue"));
}
}
private bool _VisibleTrue = true;
/// <summary>
/// Initialvalue is false
/// </summary>
public bool VisibleFalse
{
get { return _VisibleFalse; }
set
{
if (_VisibleFalse == value) return;
_VisibleFalse = value;
textBlock_false.Text = value ? "True" : "False";
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("VisibleFalse"));
}
}
private bool _VisibleFalse;
public MainWindow()
{
InitializeComponent();
textBlock_true.Text = "Application started";
textBlock_false.Text = "Application started";
}
public event PropertyChangedEventHandler PropertyChanged;
private void Button_OnClick(object sender, RoutedEventArgs e)
{
VisibleTrue = !VisibleTrue;
VisibleFalse = !VisibleTrue;
}
}
}
Preview
To prevent setting your bound property IsButtonVisible while animation performs you could add the following to your ViewModel:
private bool _animationInProgress = false;
private readonly object _animationLock = new object();
private bool _isButtonVisible = true;
public bool IsButtonVisible {
get { return _isButtonVisible; }
set {
lock (_animationLock) {
if (value == _isButtonVisible || _animationInProgress) return;
_animationInProgress = true;
}
_isButtonVisible = value;
OnPropertyChanged();
Timer animationDoneTimer = new Timer {Interval = 200, Enabled = true, AutoReset = false};
animationDoneTimer.Elapsed += (sender, args) => {
lock (_animationLock) {
_animationInProgress = false;
}
};
}
}
As second thing I would remove the Trigger:
<Trigger Property="Opacity" Value="1" >
<Setter Property="Visibility" Value="Visible"></Setter>
</Trigger>
For the behaviour, that you'd like to set Visibility to Collapsed on Opacity == 0 and Visibility to Visible on Opacity =! 0 you should do it this way:
...
<Trigger Property="Opacity" Value="0">
<Setter Property="Visibility" Value="Collapsed" />
</Trigger>
<!-- Trigger removed -->
</Style.Triggers>
<Style.Setters>
<!-- Visibilities value if Trigger Opacity == 0 does not fire -->
<Setter Property="Visibility" Value="Visible" />
<Setter Property="Height" Value="93"/>
<Setter Property="Width" Value="93"/>
<Setter Property="Opacity" Value="0"/>
</Style.Setters>
</Style>

Changing Property in ThicknessAnimation

I'm using a label in my project to show some news in moving style by thicknessanimation, but I can't change the content of label after the animation completes. What can I do?
First when the window loads I activate a thicknessanimation with the code below
<Window.Triggers>
<EventTrigger RoutedEvent="Window.Loaded">
<BeginStoryboard>
<Storyboard TargetName="MyLabel">
<ThicknessAnimation Storyboard.TargetProperty="Margin" SpeedRatio="0.8" RepeatBehavior="Forever"
FillBehavior="HoldEnd" From="0,0,0,0" To="100,0,0,0" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Window.Triggers>
Then I Set a Style on the label
<Style TargetType="Label">
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding ElementName=MyLabel, Path=Margin}" Value="100,0,0,0" />
</MultiDataTrigger.Conditions>
<Setter Property="Visibility" Value="Collapes" />
</MultiDataTrigger>
</Style.Triggers>
I tried to change the content with IsVisibleChanged but it didn't work.
Based on your code snippet the first issue is your MultiDataTrigger. You have the condition and the setter backwards try something like this and see if it works
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Property="Visibility" Value="Collapsed" />
</MultiDataTrigger.Conditions>
<Setter Binding="{Binding ElementName=Label1, Path=Margin}" Value="0,0,0,0"/>
The Condition tag is for the event or property you're looking for to trigger the Setter tag which will set the properties of the element you want to change.
Also a MultiDataTrigger is probably not the tag you need to change the margin this code should be a bit simpler
<Style TargetType="Label">
<Style.Triggers>
<Trigger Property="Visibility" Value="Collapsed">
<Setter Property="Margin" TargetName="MyLabel" Value="0,0,0,0"/>
</Trigger>
</Style.Triggers>

How to change multiple properties on mouseover

I've just started with WPF (I'm sorry if the question is too obvious), and I managed to put together this mouseover style. The background color animates to a darker color. I now want to also animate the text to white, so it's easier to read.
This is how I tried to add it, but it gives me the error "Cannot resolve all property references in the property path 'TextBlock.Foreground'. Verify that applicable objects support the properties" when I mouseover it.
<Border Background="#e6ebf3" CornerRadius="0,10,0,10" >
<Border.Style>
<Style TargetType="Border">
<Setter Property="Background" Value="#e6ebf3" />
<Setter Property="TextBlock.Foreground" Value="Black"/>
<Style.Triggers>
<EventTrigger RoutedEvent="UIElement.MouseEnter">
<BeginStoryboard>
<Storyboard>
<ColorAnimation Duration="0:0:0.1" Storyboard.TargetProperty="Background.Color" To="#6d809b" />
<ColorAnimation Duration="0:0:0.1" Storyboard.TargetProperty="TextBlock.Foreground" To="white" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="UIElement.MouseLeave">
<BeginStoryboard>
<Storyboard>
<ColorAnimation Duration="0:0:0.1" Storyboard.TargetProperty="Background.Color" To="#e6ebf3" />
<ColorAnimation Duration="0:0:0.1" Storyboard.TargetProperty="TextBlock.Foreground" To="Black" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Style.Triggers>
</Style>
</Border.Style>........
I found an alternative way without using storyboard or animations, so I'll post it just in case. Still wondering about the original one, though.
<Border CornerRadius="0,10,0,10" >
<Border.Style>
<Style TargetType="Border">
<Setter Property="Background" Value="#e6ebf3" />
<Setter Property="TextBlock.Foreground" Value="Black"/>
<Style.Triggers>
<Trigger Property ="IsMouseOver" Value="True">
<Setter Property= "Background" Value="#6d809b"/>
<Setter Property= "TextBlock.Foreground" Value="White"/>
</Trigger>
</Style.Triggers>
</Style>
</Border.Style>
...
Indirect property targeting, that being TextBlock.Foreground is described here http://msdn.microsoft.com/en-us/library/ms742451.aspx. It's basically saying, "hey I couldn't find a property called TextBlock on type button." It works with Background.Color because the Background Property does exist on Button and it's of type ColorBrush which itself has a property of type Color.

Animate background colour on exitaction

I'm trying to animate the background colour on a grid to change, once an event happens, but I can't get it working, I can get it to change colour immediately (via data triggers), but as soon as I try to introduce an animation into it, then I can't get it working (the animation doesn't seem to come into effect).
This is the current XAML I'm using (though I've tried various variations and cannot get it to animate):
<DataTrigger Binding="{Binding ElementName=me, Path=Viewed}" Value="False">
<Setter Property="Background" Value="LightYellow" />
<DataTrigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation Duration="00:00:02" To="White" Storyboard.TargetProperty="(Grid.Background).(SolidColorBrush.Color)"/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.ExitActions>
</DataTrigger>
<!--
<DataTrigger Binding="{Binding ElementName=me, Path=Viewed}" Value="True">
<Setter Property="Background" Value="White" />
</DataTrigger>
-->
Where Viewed is a dependency property (bool) on my Control. Any hints in the right direction would be appreciated. I've also tried setting it as an EventTrigger on a raised event which happens when the bool switches to true.
Thanks to Clemens helps, figured out what I needed to do:
<SolidColorBrush x:Key="GridColourBrush" Color="LightYellow" />
<Style x:Key="GridStyle" TargetType="Grid">
<Setter Property="Background" Value="White" />
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=me, Path=Viewed}" Value="False">
<Setter Property="Background" Value="{StaticResource GridColourBrush}" />
<DataTrigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation Duration="00:00:02" To="White" Storyboard.TargetProperty="(Grid.Background).(SolidColorBrush.Color)"/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
<!-- snipped stuff -->
<Grid MinWidth="525" x:Name="ContainerGrid" Style="{StaticResource GridStyle}" Background="{StaticResource GridColourBrush}" />
So setting the background to be flat white by default, then if the DP bool is false, change the background to the static solid colour brush, which I can then animate via the exit actions.
What i meant was simply that instead of
<Grid Background="LightYellow">
</Grid>
you would have to write
<Grid>
<Grid.Background>
<SolidColorBrush Color="LightYellow" />
</Grid.Background>
</Grid>
No need to have an extra resource.

'Setter' object cannot be added to 'EventTrigger'?

I get the following error on the WPF code bellow:
'Setter' object cannot be added to 'EventTrigger'. The given object must be an instance of TriggerAction or a derived type.
<Style x:Key="LinkLabel" TargetType="{x:Type Label}">
<Setter Property="FontFamily" Value="Tahoma"/>
<Setter Property="FontSize" Value="12"/>
<Setter Property="Foreground" Value="DarkBlue"/>
<Style.Triggers>
<EventTrigger RoutedEvent="MouseEnter" >
<Setter Property="Cursor" Value="Hand"/>
</EventTrigger>
<EventTrigger RoutedEvent="MouseDown" >
<Setter Property="Foreground" Value="Red"/>
</EventTrigger>
<EventTrigger RoutedEvent="MouseUp" >
<Setter Property="Foreground" Value="DarkBlue"/>
</EventTrigger>
</Style.Triggers>
</Style>
Can anyone explain and point me in the right direction ?
MadSeb
Option 1 - Use BeginStoryboard like ChrisF said
Option 2 - Don't use EventTrigger - for example, for a label that changes background color when you mouse over it use:
<Style TargetType="Label">
<Setter Property="Background" Value="Blue"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="true" >
<Setter Property="Background" Value="Red"/>
</Trigger>
</Style.Triggers>
</Style>
Unfortunately there is no property IsMouseDown you can use.
About your example:
You don't have to set the cursor on MouseEnter, just set the Cursor property and it will only affect the mouse cursor when the mouse is over the control.
If you want to create an hyperlink control don't use a label, eitehr use a Button with a custom template (this will give you the Click event and IsPressed property) or, even better - use the Hyperlink class like this:
<TextBlock><Hyperlink>This is a link</Hyperlink></TextBlock>
This will have all the styling you wanted.
You must use a TriggerAction to change the values as in this example from the EventTriggers MSDN page:
<Style TargetType="Rectangle">
<Setter Property="Width" Value="50" />
<Setter Property="Height" Value="50" />
<Setter Property="Margin" Value="20" />
<Setter Property="HorizontalAlignment" Value="Left" />
<Style.Triggers>
<EventTrigger RoutedEvent="MouseEnter">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation To="300" Duration="0:0:1.5"
AccelerationRatio="0.10" DecelerationRatio="0.25"
Storyboard.TargetProperty="(Canvas.Width)" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="MouseLeave">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Duration="0:0:1.5"
AccelerationRatio="0.10" DecelerationRatio="0.25"
Storyboard.TargetProperty="(Canvas.Width)" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Style.Triggers>
</Style>

Resources