Jeff LaFay
Jeff LaFay

Reputation: 13350

WPF Controls: How to Reference Resources in Animations?

I have written a control and successfully created a storyboard to cause an animation during triggered events. It changes the fill of an ellipse for a duration of time. Instead of writing a new RadialGradientBrush each time I need to change the fill, I provided two of them in the resources.

EDIT: I have an Ellipse that is the main component to the control and is what is affected by the animation. It's implementation is simple and looks like this:

<Ellipse Name="myEllipse" Style="{StaticResource DimStyle}" />

When I add it to the storyboard (instead of referencing the brush as a resource), my animation works as intended. When I reference the brush as a resource I get this exception:

"Cannot find resource named 'IlluminatedStyle'. Resource names are case sensitive."

Inside of the storyboard, this is where it is currently referenced:

<UserControl.Resources>
    <Storyboard x:Key="Foo">
        <ObjectAnimationUsingKeyFrames>
            <ObjectAnimationUsingKeyFrames.KeyFrames>
                <DiscreteObjectKeyFrame KeyTime="0:0:0.01" Value="{StaticResource IlluminatedStyle}" />
                <DiscreteObjectKeyFrame KeyTime="0:0:0.85" Value="{StaticResource DimStyle}" />
            </ObjectAnimationUsingKeyFrames.KeyFrames>
        </ObjectAnimationUsingKeyFrames>
     </Storyboard>
</UserControl.Resources>

The styles are closely identical and only the GradientStop color properties differ so I'll provide only one style for an example.

The Style Referenced

<UserControl.Resources>
    <Style x:Key="IlluminatedStyle" TargetType="Ellipse">
        <Setter Property="Fill">
            <Setter.Value>
                <RadialGradientBrush>
                    <GradientStop Color="#FF215416" Offset="1"/>
                    <GradientStop Color="#FE38DA2E" Offset="0"/>
                    <GradientStop Color="#FE81FF79" Offset="0.688"/>
                </RadialGradientBrush>
            </Setter.Value>
        </Setter>
    </Style>
</UserControl.Resources>

So how do I correctly reference a style such as this in my Storyboard?

Note: The Storyboard and Style are both contained within the same UserControl.Resources tag but broken out for this example.

EDIT
I put the Style before the Storyboard in UserControl.Resources and now I get an exception stating:

  "This Freezable cannot be frozen.
   at System.Windows.Freezable.Freeze()
   at System.Windows.Freezable.GetCurrentValueAsFrozen()
   at System.Windows.Media.Animation.TimelineCollection.GetCurrentValueAsFrozenCore(Freezable source)
   at System.Windows.Freezable.CloneCoreCommon(Freezable sourceFreezable, Boolean useCurrentValue, Boolean cloneFrozenValues)
   at System.Windows.Media.Animation.Timeline.GetCurrentValueAsFrozenCore(Freezable sourceFreezable)
   at System.Windows.Freezable.GetCurrentValueAsFrozen()
   at System.Windows.Media.Animation.Clock..ctor(Timeline timeline)
   at System.Windows.Media.Animation.TimelineGroup.AllocateClock()
   at System.Windows.Media.Animation.Clock.AllocateClock(Timeline timeline, Boolean hasControllableRoot)"

Upvotes: 2

Views: 1352

Answers (2)

Jeff LaFay
Jeff LaFay

Reputation: 13350

Seeing that I am new to WPF and XAML I made the mistake of making my resources a style and did not realize that I could have simply made the brushes a resource and avoid styles altogether.

I kept the reference to the DiscreteObjectKeyFrames' values as static to the new brush resources. I changed the Ellipse to this:

<Ellipse Name="myEllipse" Fill="{StaticResource DimBrush" />

The style property was removed and I assigned the brush to the fill property directly. In the ObjectAnimationUsingKeyFrames tag I added Fill as the Storyboard.TargetProperty since I was no longer using a style to dress up the fill. The DiscreteObjectKeyFrames now look like this:

<DiscreteObjectKeyFrame KeyTime="0:0:0.01" Value="{StaticResource IlluminatedBrush}" />
<DiscreteObjectKeyFrame KeyTime="0:0:0.85" Value="{StaticResource DimBrush}" />

My resources are much simpler without being wrapped in a style and IMO, more elegant. Also the brushes are defined before the animation in my final solution.

<UserControl.Resources>
    <RadialGradientBrush x:Key="DimBrush" >
        <GradientStop Color="#FF21471A" Offset="1"/>
        <GradientStop Color="#FF33802F" Offset="0"/>
        <GradientStop Color="#FF35932F" Offset="0.688"/>
    </RadialGradientBrush>
    <RadialGradientBrush x:Key="IlluminatedBrush">
        <GradientStop Color="#FF215416" Offset="1"/>
        <GradientStop Color="#FE38DA2E" Offset="0"/>
        <GradientStop Color="#FE81FF79" Offset="0.688"/>
    </RadialGradientBrush>
    <!-- Storyboard code follows... -->
</UserControl.Resources>

Everything is now working as intended. The best assumption I can make is that styles are not freezable since they were the components that I removed and I no longer receive exceptions regarding a freezable that cannot be frozen.

Upvotes: 1

Jon
Jon

Reputation: 437376

There are three reasons why a Freezable cannot be frozen:

  • It has animated or data bound properties.
  • It has properties that are set by a dynamic resource.
  • It contains Freezable sub-objects that cannot be frozen.

So, first find out which Freezable is causing trouble and then check the above.

Upvotes: 3

Related Questions