Animate a linear brush using a data trigger - wpf

I am trying to animate a linear brush on a border using a data trigger but have come accross a problem where I cannot use the TargetName
My code is as follows, can anyone suggest a way to resolve this?
<Border Grid.Row="2" BorderThickness="10" Height="100" Width="100" >
<Border.BorderBrush>
<LinearGradientBrush>
<GradientStop Color="Yellow" Offset="0.0" />
<GradientStop x:Name="gradient" Color="Orange" Offset="0.5" />
<GradientStop Color="Yellow" Offset="1.0" />
</LinearGradientBrush>
</Border.BorderBrush>
<Border.Resources>
<Style TargetType="Border">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=testBrdrWin, Path=Pulse}" Value="true">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="gradient"
Storyboard.TargetProperty="Offset"
From="0" To="1" Duration="0:0:1"
AutoReverse="True" RepeatBehavior="Forever"
/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=testBrdrWin, Path=Pulse}" Value="true">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="gradient"
Storyboard.TargetProperty="Offset"
To="0.5" Duration="0:0:01"
AutoReverse="False"
/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Resources>
</Border>
Thanks

You can't use Storyboard.TargetName here. You have to use a complete PropertyPath Syntax.
LinearGradientBrush has to be in Style itself.
In this example code I have removed all special things and therefore it will work stand alone too if you MouseOver the Border. Adapt it for your needs again.
<Border BorderThickness="10" Height="100" Width="100" >
<Border.Resources>
<Style TargetType="Border">
<Setter Property="BorderBrush">
<Setter.Value>
<LinearGradientBrush>
<GradientStop Color="Yellow" Offset="0.0" />
<GradientStop Color="Red" Offset="0.5" />
<GradientStop Color="Yellow" Offset="1.0" />
</LinearGradientBrush>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding IsMouseOver, RelativeSource={RelativeSource Self}}" Value="true">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetProperty="BorderBrush.(GradientBrush.GradientStops)[1].(GradientStop.Offset)"
From="0" To="1" Duration="0:0:1"
AutoReverse="True" RepeatBehavior="Forever"
/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Resources>
</Border>

Related

WPF TabItem style when mouse left button is down

I am defining a Style for WPF TabControl TabItem.
I want to show a slight "pushed down" effect on TabItem when mouse (left button) is pressed down and the TabItem is not selected but I cannot find the Trigger for this.
I have tried to define a MultiTrigger with IsMouseLeftButtonDown and IsPressed properties but neither one is recognized.
<Style TargetType="{x:Type TabItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TabItem">
<Border Name="bd" BorderThickness="1,1,0,0">
<Grid>
<ContentPresenter VerticalAlignment="Center" HorizontalAlignment="Center"
ContentSource="Header"/>
</Grid>
</Border>
<ControlTemplate.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsMouseLeftButtonDown" Value="True" /> <!--NOT RECOGNIZED-->
<Condition Property="IsSelected" Value="False" />
</MultiTrigger.Conditions>
<Setter TargetName="bd" Property="Background" >
<Setter.Value>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="Green" Offset="0"/>
<GradientStop Color="Yellow" Offset="1"/>
</LinearGradientBrush>
</Setter.Value>
</Setter>
</MultiTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
How to set a Trigger that gets into action when mouse left button is pressed down on a TabItem ?
EDIT
I tried EventTrigger but I don't see any effect with the below
<EventTrigger RoutedEvent="UIElement.PreviewMouseLeftButtonDown">
<BeginStoryboard>
<Storyboard>
<ColorAnimation Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)" To="Green" Duration="0:0:3" />
</Storyboard>
<BeginStoryboard/>
<EventTrigger/>
Can it be achieved with this way somehow ?
This example shows you, how to work with EventTriggers.
Note
You might have to set your Highlighting-Logic fully in those Triggers, since values are overridden everytime, the Trigger fires.
<EventTrigger RoutedEvent="PreviewMouseDown" >
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard >
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="bd" Storyboard.TargetProperty="Background" Duration="0:0:3" BeginTime="0" AutoReverse="True">
<ObjectAnimationUsingKeyFrames.KeyFrames>
<DiscreteObjectKeyFrame KeyTime="0:0:0" Value="{x:Static Brushes.Green}" />
</ObjectAnimationUsingKeyFrames.KeyFrames>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
<EventTrigger RoutedEvent="PreviewMouseUp" >
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard >
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="bd" Storyboard.TargetProperty="Background" Duration="0:0:3" BeginTime="0" AutoReverse="True">
<ObjectAnimationUsingKeyFrames.KeyFrames>
<DiscreteObjectKeyFrame KeyTime="0:0:0" Value="{x:Static Brushes.Transparent}" />
</ObjectAnimationUsingKeyFrames.KeyFrames>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>

Stop / start storyboard animation based on Visibility

I have an animation that currently starts when a Control is loaded (the animation is essentially a waiting spinner, that is applied to an empty ContentControl).
The animation however will constantly spin taking up resources. What I'd like is for the animation to start / stop based on whether the animation control is visible or not, is this possible?
<Canvas.Triggers>
<EventTrigger RoutedEvent="ContentControl.Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="SpinnerRotate"
Storyboard.TargetProperty="Angle"
From="0" To="360" Duration="0:0:01.3"
RepeatBehavior="Forever" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Canvas.Triggers>
I must have this working for both Silverlight and WPF.
I have created an example of spinning an Ellipse based on the Visibility property. Perhaps you can use something from this.
<Canvas>
<Ellipse x:Name="Circle" Width="30" Height="30"
Canvas.Left="50"
Canvas.Top="50">
<Ellipse.Fill>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="Black" Offset="0"/>
<GradientStop Color="White" Offset="1"/>
</LinearGradientBrush>
</Ellipse.Fill>
<Ellipse.RenderTransform>
<RotateTransform x:Name="SpinnerRotate" CenterX="15" CenterY="15"/>
</Ellipse.RenderTransform>
<Ellipse.Style>
<Style TargetType="Ellipse">
<Style.Triggers>
<Trigger Property="Visibility" Value="Visible">
<Trigger.EnterActions>
<BeginStoryboard x:Name="SpinStoryboard">
<Storyboard >
<DoubleAnimation Storyboard.TargetProperty="RenderTransform.Angle"
From="0" To="360" Duration="0:0:01.3"
RepeatBehavior="Forever" />
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<StopStoryboard BeginStoryboardName="SpinStoryboard"></StopStoryboard>
</Trigger.ExitActions>
</Trigger>
</Style.Triggers>
</Style>
</Ellipse.Style>
</Ellipse>
</Canvas>
Might not be elegant, but works.
<Border x:Name="square" Height="20" Width="20" Background="Aqua">
<Border.Triggers>
<EventTrigger RoutedEvent="Loaded">
<BeginStoryboard>
<Storyboard x:Name="spinner">
<DoubleAnimation
Storyboard.TargetName="square"
Storyboard.TargetProperty="Opacity"
From="1" To="0" Duration="0:0:01.3"
AutoReverse="True"
RepeatBehavior="Forever" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Border.Triggers>
<Border.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding Source={RelativeSource Self}, Path=Visibility}" Value="{x:Static Visibility.Collapsed}">
<DataTrigger.EnterActions>
<StopStoryboard BeginStoryboardName="spinner"/>
</DataTrigger.EnterActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
</Border>

WPF IDataErrorInfo icon location right

I have a validation template as below. But we can set the error icon either inside control or left of the control. Can you please tell me how can i make it blink at the right of the control (Outside the textBox and right)
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
>
<Storyboard x:Key="FlashErrorIcon">
<ObjectAnimationUsingKeyFrames BeginTime="00:00:00"
Storyboard.TargetProperty="(UIElement.Visibility)">
<DiscreteObjectKeyFrame KeyTime="00:00:00" Value="{x:Static Visibility.Hidden}"/>
<DiscreteObjectKeyFrame KeyTime="00:00:00.2000000" Value="{x:Static Visibility.Visible}"/>
<DiscreteObjectKeyFrame KeyTime="00:00:00.4000000" Value="{x:Static Visibility.Hidden}"/>
<DiscreteObjectKeyFrame KeyTime="00:00:00.6000000" Value="{x:Static Visibility.Visible}"/>
<DiscreteObjectKeyFrame KeyTime="00:00:00.8000000" Value="{x:Static Visibility.Hidden}"/>
<DiscreteObjectKeyFrame KeyTime="00:00:01" Value="{x:Static Visibility.Visible}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
<Style x:Key="myErrorTemplate" TargetType="Control">
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate>
<DockPanel LastChildFill="True">
<Ellipse DockPanel.Dock="Left"
ToolTip="{Binding ElementName=myTextbox,
Path=AdornedElement.(Validation.Errors)[0].ErrorContent}"
Width="15" Height="15"
Margin="-25,0,0,0"
StrokeThickness="1" Fill="Red" >
<Ellipse.Stroke>
<LinearGradientBrush EndPoint="1,0.5" StartPoint="0,0.5">
<GradientStop Color="#FFFA0404" Offset="0"/>
<GradientStop Color="#FFC9C7C7" Offset="1"/>
</LinearGradientBrush>
</Ellipse.Stroke>
<Ellipse.Triggers>
<EventTrigger RoutedEvent="FrameworkElement.Loaded">
<BeginStoryboard Storyboard="{StaticResource FlashErrorIcon}"/>
</EventTrigger>
</Ellipse.Triggers>
</Ellipse>
<TextBlock DockPanel.Dock="Left"
ToolTip="{Binding ElementName=myControl,
Path=AdornedElement.(Validation.Errors)[0].ErrorContent}"
Foreground="White"
FontSize="11pt"
Margin="-15,5,0,0" FontWeight="Bold">!
<TextBlock.Triggers>
<EventTrigger RoutedEvent="FrameworkElement.Loaded">
<BeginStoryboard Storyboard="{StaticResource FlashErrorIcon}"/>
</EventTrigger>
</TextBlock.Triggers>
</TextBlock>
<Border BorderBrush="Red" BorderThickness="1">
<AdornedElementPlaceholder Name="myControl"/>
</Border>
</DockPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip"
Value="{Binding RelativeSource={x:Static RelativeSource.Self},
Path=(Validation.Errors)[0].ErrorContent}"/>
</Trigger>
</Style.Triggers>
</Style>
<Style TargetType="TextBox" BasedOn="{StaticResource myErrorTemplate}" />
Change the location of the error icon via modifications to the template.

WPF - Animation on IsSelected

I have an Ellipse inside another control that gets its Fill changed when the parent is selected.
<Style TargetType="TabItem">
<Setter Property="IsEnabled" Value="False" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TabItem">
<Grid MinWidth="150">
<Border BorderBrush="Transparent" BorderThickness="0">
<StackPanel Orientation="Vertical">
<ContentPresenter HorizontalAlignment="Center" ContentSource="Header" />
<Ellipse Name="Ellipse" Stroke="Black" StrokeThickness="1" Width="24" Height="24" Margin="5">
<Ellipse.Fill>
<LinearGradientBrush StartPoint="0,1" EndPoint="1,0">
<GradientStop x:Name="FirstGradient" Color="Transparent" Offset="0.3" />
<GradientStop x:Name="SecondGradient" Color="Transparent" Offset="0.75" />
</LinearGradientBrush>
</Ellipse.Fill>
</Ellipse>
</StackPanel>
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation Storyboard.TargetName="FirstGradient" Storyboard.TargetProperty="Color"
From="Transparent" To="#FF9221" Duration="0:0:0.2" />
</Storyboard>
</BeginStoryboard>
<BeginStoryboard>
<Storyboard>
<ColorAnimation Storyboard.TargetName="SecondGradient" Storyboard.TargetProperty="Color"
From="Transparent" To="#FFCFA5" Duration="0:0:0.2" />
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Works fine. What I've not managed to do though is to change the Fill back to default when the parent is no longer selected. How do I do that?
if you are looking for tabcontrol style
just see if this can help you out in some way.
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="WpfApplication16.MainWindow"
x:Name="Window"
Title="MainWindow"
Width="640" Height="480">
<Window.Resources>
<Style TargetType="TabItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TabItem">
<ControlTemplate.Resources>
<Storyboard x:Key="Storyboard1">
<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="Ellipse" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[0].(GradientStop.Color)">
<SplineColorKeyFrame KeyTime="00:00:00" Value="Transparent"/>
<SplineColorKeyFrame KeyTime="00:00:00.5000000" Value="#00FE3737"/>
</ColorAnimationUsingKeyFrames>
<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="Ellipse" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[1].(GradientStop.Color)">
<SplineColorKeyFrame KeyTime="00:00:00" Value="Transparent"/>
<SplineColorKeyFrame KeyTime="00:00:00.5000000" Value="#FFFF2525"/>
</ColorAnimationUsingKeyFrames>
</Storyboard>
</ControlTemplate.Resources>
<Grid MinWidth="150">
<Border BorderBrush="Transparent" BorderThickness="0">
<StackPanel Orientation="Vertical">
<ContentPresenter HorizontalAlignment="Center" ContentSource="Header" />
<Ellipse Name="Ellipse" Stroke="Black" StrokeThickness="1" Width="24" Height="24" Margin="5">
<Ellipse.Fill>
<LinearGradientBrush StartPoint="0,1" EndPoint="1,0">
<GradientStop x:Name="FirstGradient" Color="Transparent" Offset="0.3" />
<GradientStop x:Name="SecondGradient" Color="Transparent" Offset="0.75" />
</LinearGradientBrush>
</Ellipse.Fill>
</Ellipse>
</StackPanel>
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="Selector.IsSelected" Value="True">
<Trigger.ExitActions>
<StopStoryboard BeginStoryboardName="Storyboard1_BeginStoryboard"/>
</Trigger.ExitActions>
<Trigger.EnterActions>
<BeginStoryboard x:Name="Storyboard1_BeginStoryboard" Storyboard="{StaticResource Storyboard1}"/>
</Trigger.EnterActions>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid x:Name="LayoutRoot">
<TabControl>
<TabItem Header="First"></TabItem>
<TabItem Header="Second" IsSelected="true"></TabItem>
<TabItem Header="Last"></TabItem>
</TabControl>
</Grid>
The problem was that I had defined the default look of the Ellipse within the template,
<Ellipse Name="Ellipse" Stroke="Black" StrokeThickness="1" Width="24" Height="24" Margin="5">
<Ellipse.Fill>
<LinearGradientBrush StartPoint="0,1" EndPoint="1,0">
<GradientStop x:Name="FirstGradient" Color="Transparent" Offset="0.3" />
<GradientStop x:Name="SecondGradient" Color="Transparent" Offset="0.75" />
</LinearGradientBrush>
</Ellipse.Fill>
</Ellipse>
This caused so that when a TabItem no longer was selected, it didn't change back to it's default look.
To solve this I just TemplateBind the Ellipse.Fill to the Background of the TabItem.
Try with adding that:
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation Storyboard.TargetName="FirstGradient" Storyboard.TargetProperty="Color"
To="Transparent" From="#FF9221" Duration="0:0:0" />
</Storyboard>
</BeginStoryboard>
<BeginStoryboard>
<Storyboard>
<ColorAnimation Storyboard.TargetName="SecondGradient" Storyboard.TargetProperty="Color"
To="Transparent" From="#FFCFA5" Duration="0:0:0" />
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
to your Triggers

Trouble animating RadialGradientBrush in WPF

I'm trying to animate a RadialGradientBrush in my application. I get the super helpful exception:
Additional information: 'System.Windows.Style' value cannot be assigned to property 'Style' of object 'System.Windows.Controls.Border'. '[Unknown]' property does not point to a DependencyObject in path '(0).(1).[0].(2)'. Error at object 'System.Windows.Style' in markup file 'Eng.Modules.Core;component/system/grid/systemgridview.xaml' Line 252 Position 51.
I know it's something wrong with the indirect property targeting or partial path qualification in my DoubleAnimation's Storyboard.TargetProperty attribute. Any ideas?
<Border>
<Border.Resources>
<RadialGradientBrush x:Key="SomeBrush">
<RadialGradientBrush.GradientStops>
<GradientStop Color="White" Offset="0" />
<GradientStop Color="Gold" Offset="1" />
</RadialGradientBrush.GradientStops>
</RadialGradientBrush>
</Border.Resources>
<Border.Style>
<Style TargetType="{x:Type Border}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsEnabled, RelativeSource={RelativeSource Self}}" Value="True">
<Setter Property="Background" Value="{StaticResource SomeBrush}" />
<DataTrigger.EnterActions>
<BeginStoryboard x:Name="SomeStoryBoard">
<Storyboard>
<!-- RIGHT HERE -->
<DoubleAnimation
Storyboard.TargetProperty="(Border.Background).(GradientBrush.GradientStops)[0].(GradientStop.Offset)"
From="0" To="1" Duration="0:0:1"
RepeatBehavior="Forever"
AutoReverse="True" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<RemoveStoryboard BeginStoryboardName="SomeStoryBoard" />
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
</Border>
The first problem is that you are setting the background to a gradient brush in your DataTrigger. Because this gets applied later, the animation won't be able to find the brush (hence the cryptic error about not finding a dependency property). So the first thing I did was set the border's background to the brush manually, rather than in the trigger.
The second problem was how you were setting up the target property. You don't need to use the parenthesis syntax- it works just fine as follows: Background.GradientStops[0].Offset.
With these changes the border animates perfectly; here is the final mark-up:
<Border>
<Border.Background>
<RadialGradientBrush>
<RadialGradientBrush.GradientStops>
<GradientStop Color="White" Offset="0" />
<GradientStop Color="Gold" Offset="1" />
</RadialGradientBrush.GradientStops>
</RadialGradientBrush>
</Border.Background>
<Border.Style>
<Style TargetType="{x:Type Border}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsEnabled, RelativeSource={RelativeSource Self}}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard x:Name="SomeStoryBoard">
<Storyboard>
<!-- RIGHT HERE -->
<DoubleAnimation
Storyboard.TargetProperty="Background.GradientStops[0].Offset"
From="0" To="1" Duration="0:0:1"
RepeatBehavior="Forever"
AutoReverse="True" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<RemoveStoryboard BeginStoryboardName="SomeStoryBoard" />
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
</Border>
My Answer as per the comments in the code sample.
I've removed the MultiDataTrigger from my first post, as I can't get this working myself with bound collections. I may have to ask this to see if anyone has an answer to the issue.
<Grid>
<Grid.Resources>
<!-- Don't use a ControlTemplate. This destroys your control structure,
which doesn't make sense if all you want to do is animate the background. -->
<Style x:Key="MyAnimatedFeatureStyle" TargetType="Button">
<Style.Resources>
<RadialGradientBrush x:Key="GoldRadialGradientBrush">
<RadialGradientBrush.GradientStops>
<GradientStop Color="White" Offset="0" />
<GradientStop Color="Gold" Offset="1" />
</RadialGradientBrush.GradientStops>
</RadialGradientBrush>
<Storyboard RepeatBehavior="Forever" AutoReverse="False" x:Key="SomeStoryBoard">
<DoubleAnimation Storyboard.TargetProperty="Background.GradientStops[0].Offset" From="0" To="1" Duration="0:0:1" RepeatBehavior="Forever" AutoReverse="True" />
</Storyboard>
</Style.Resources>
<Style.Triggers>
<!-- Your primary binding condition. Whatever this may be. -->
<DataTrigger Binding="{Binding Path=IsSOMTHINGSET}" Value="true" >
<!-- The Background is here in the setter, because we only want the background colored and animated on the binding condition. -->
<Setter Property="Background" Value="{StaticResource GoldRadialGradientBrush}" />
<DataTrigger.EnterActions>
<BeginStoryboard x:Name="BorderStoryBoard" Storyboard="{StaticResource SomeStoryBoard}" />
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<RemoveStoryboard BeginStoryboardName="BorderStoryBoard" />
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Grid.Resources>
<Button Style="{StaticResource MyAnimatedFeatureStyle}" />
</Grid>
I actually developed a solution to the problem just as Charlie posted his. It looks like we came up with close to the same thing. Just posting mine for reference:
<Button>
<Button.Style>
<Style TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<ControlTemplate.Resources>
<RadialGradientBrush x:Key="GoldRadialGradientBrush">
<RadialGradientBrush.GradientStops>
<GradientStop Color="White" Offset="0" />
<GradientStop Color="Gold" Offset="1" />
</RadialGradientBrush.GradientStops>
</RadialGradientBrush>
<Storyboard x:Key="SomeStoryBoard">
<DoubleAnimation
Storyboard.TargetProperty="(Border.Background).(GradientBrush.GradientStops)[0].Offset"
From="0" To="1" Duration="0:0:1"
RepeatBehavior="Forever"
AutoReverse="True" />
</Storyboard>
</ControlTemplate.Resources>
<Grid>
<Border Background="{StaticResource GoldRadialGradientBrush}">
<Border.Style>
<Style TargetType="{x:Type Border}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsEnabled, RelativeSource={RelativeSource Self}}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard x:Name="BorderStoryBoard" Storyboard="{StaticResource SomeStoryBoard}" />
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<RemoveStoryboard BeginStoryboardName="BorderStoryBoard" />
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Button.Style>
</Button>

Resources