dotnet/wpf · error · ArgumentException

Animation_DependencyPropertyIsNotAnimatable

Animation_DependencyPropertyIsNotAnimatable

Error message

SR.Animation_DependencyPropertyIsNotAnimatable (Animation_DependencyPropertyIsNotAnimatable)

What it means

ApplyAnimationClock was called with a DependencyProperty that WPF does not consider animatable (AnimationStorage.IsPropertyAnimatable returned false). WPF only allows animating dependency properties registered with the 'readable, writable, animatable' (Media.AnimationRead) flags, i.e. registered via DependencyProperty.Register with animate support. This ArgumentException protects the animation subsystem from targets that cannot host animation clocks.

Solutions

  1. Verify the DependencyProperty you pass is a real, writable, animatable DP (check Animatable.GetLocalValueEnumerator or the property's metadata); use the static XXXProperty field (e.g. UIElement.OpacityProperty) rather than a looked-up name.
  2. If it is your own property, re-register it with the animation-capable metadata (AddOwner/OverrideMetadata from an animatable owner or register with the appropriate framework flags).
  3. For read-only properties, animate a substitute (e.g. a bound writable property) or use PropertyPath-based storyboard animation on an animatable wrapper.

Example fix

// before
anim.ApplyAnimationClock(SomeControl.MyPropProperty, clock); // MyProp registered without animatable support
// after
anim.ApplyAnimationClock(UIElement.OpacityProperty, clock); // well-known animatable DP
Defensive patterns

Strategy: validation

Validate before calling

if (dp == null || !AnimationStorage.IsPropertyAnimatable(target, dp))
    throw new ArgumentException($"{dp?.Name} on {target.GetType()} is not animatable");

Type guard

static bool IsAnimatable(DependencyObject o, DependencyProperty dp) => dp != null && !dp.ReadOnly && AnimationStorage.IsPropertyAnimatable(o, dp);

Try / catch

try { target.ApplyAnimationClock(dp, clock); }
catch (ArgumentException ex) when (ex.ParamName == nameof(dp)) { /* log: property not animatable */ }

Prevention

When it happens

Trigger: Calling animatable.ApplyAnimationClock(dp, clock) where dp was registered without animation support (e.g. a custom DependencyProperty registered without the animatable flag, a read-only property, or a property that is not a DP at all resolved by name lookup).

Common situations: Custom controls registering DPs without animatable metadata; animating read-only DPs (e.g. ActualWidth); using reflection/property lookup to grab the wrong DP; porting code from a library version where the property was not yet animatable.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14). Data as JSON: /api/errors/0dc27b36d18b4aa3. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/Animation/Generated/Animatable.cs:70

        /// <param name="clock">
        /// The AnimationClock that will animate the property. If parameter is null
        /// then animations will be removed from the property if handoffBehavior is
        /// SnapshotAndReplace; otherwise the method call will have no result.
        /// </param>
        /// <param name="handoffBehavior">
        /// Determines how the new AnimationClock will transition from or
        /// affect any current animations on the property.
        /// </param>
        public void ApplyAnimationClock(
            DependencyProperty dp,
            AnimationClock clock,
            HandoffBehavior handoffBehavior)
        {
            ArgumentNullException.ThrowIfNull(dp);

            if (!AnimationStorage.IsPropertyAnimatable(this, dp))
            {
                throw new ArgumentException(SR.Format(SR.Animation_DependencyPropertyIsNotAnimatable, dp.Name, this.GetType()), nameof(dp));
            }

            if (clock != null
                && !AnimationStorage.IsAnimationValid(dp, clock.Timeline))
            {
                throw new ArgumentException(SR.Format(SR.Animation_AnimationTimelineTypeMismatch, clock.Timeline.GetType(), dp.Name, dp.PropertyType), nameof(clock));
            }

            if (!HandoffBehaviorEnum.IsDefined(handoffBehavior))
            {
                throw new ArgumentException(SR.Animation_UnrecognizedHandoffBehavior);
            }

            if (IsSealed)
            {
                throw new InvalidOperationException(SR.Format(SR.IAnimatable_CantAnimateSealedDO, dp, this.GetType()));
            }

View on GitHub (pinned to 81131a70a4)