{"record":{"id":"45e75c5620142f76","repo":"dotnet/wpf","slug":"cannotchangeaftersealed-sr-format-sr-setstoryboardspeedratio","errorCode":"CannotChangeAfterSealed","errorMessage":"SR.Format(SR.CannotChangeAfterSealed, \"SetStoryboardSpeedRatio\")","messagePattern":"SR\\.Format\\(SR\\.CannotChangeAfterSealed, \"SetStoryboardSpeedRatio\"\\)","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Media/Animation/SetStoryboardSpeedRatio.cs","lineNumber":37,"sourceCode":"    /// </summary>\n    public sealed class SetStoryboardSpeedRatio : ControllableStoryboardAction\n{\n    /// <summary>\n    ///     A speed ratio to use for this action.  If it is never explicitly\n    /// specified, it is 1.0.\n    /// </summary>\n    [DefaultValue(1.0)]\n    public double SpeedRatio\n    {\n        get\n        {\n            return _speedRatio;\n        }\n        set\n        {\n            if (IsSealed)\n            {\n                throw new InvalidOperationException(SR.Format(SR.CannotChangeAfterSealed, \"SetStoryboardSpeedRatio\"));\n            }\n\n            _speedRatio = value;\n        }\n    }\n\n    /// <summary>\n    ///     Called when it's time to execute this storyboard action\n    /// </summary>\n    internal override void Invoke( FrameworkElement containingFE, FrameworkContentElement containingFCE, Storyboard storyboard )\n    {\n        Debug.Assert( containingFE != null || containingFCE != null,\n            \"Caller of internal function failed to verify that we have a FE or FCE - we have neither.\" );\n\n        if( containingFE != null )\n        {\n            storyboard.SetSpeedRatio(containingFE, SpeedRatio);\n        }","sourceCodeStart":19,"sourceCodeEnd":55,"githubUrl":"https://github.com/dotnet/wpf/blob/81131a70a4c573cd62748a5c36908fc4d662daa9/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Media/Animation/SetStoryboardSpeedRatio.cs#L19-L55","documentation":"SetStoryboardSpeedRatio.SpeedRatio's setter throws InvalidOperationException when the action object is sealed. Like other controllable storyboard actions, it becomes read-only once attached to a trigger/storyboard and put into use.","triggerScenarios":"Setting SpeedRatio on a SetStoryboardSpeedRatio instance after it has been sealed — e.g. mutating a shared or template-declared action at runtime.","commonSituations":"Dynamically updating the speed ratio by reusing one SetStoryboardSpeedRatio object instead of creating a new one per trigger invocation.","solutions":["Create a new SetStoryboardSpeedRatio with the desired SpeedRatio for each change.","Set SpeedRatio before the action is attached to any EventTrigger or storyboard.","Alternatively call Storyboard.SetSpeedRatio directly on the target's clock."],"exampleFix":"// before\nsharedSpeedAction.SpeedRatio = 2.0; // throws once sealed\n\n// after\nvar action = new SetStoryboardSpeedRatio { Storyboard = targetStoryboard, SpeedRatio = 2.0 };","handlingStrategy":"type-guard","validationCode":"if (action.IsSealed) action = new SetStoryboardSpeedRatio { Storyboard = action.Storyboard, SpeedRatio = newRatio };","typeGuard":"static SetStoryboardSpeedRatio EnsureMutable(SetStoryboardSpeedRatio a, double ratio) => a.IsSealed ? new SetStoryboardSpeedRatio { Storyboard = a.Storyboard, SpeedRatio = ratio } : a;","tryCatchPattern":"try { action.SpeedRatio = ratio; } catch (InvalidOperationException) { action = new SetStoryboardSpeedRatio { /* reconfigure */ }; }","preventionTips":["Create a new SetStoryboardSpeedRatio per speed change","Configure properties before attaching to triggers","Use Storyboard.SetSpeedRatio for runtime changes"],"tags":["wpf","storyboard","animation","sealed-object","immutable-state"],"backgroundTag":"invalid-state-transition","analyzedSha":"81131a70a4c573cd62748a5c36908fc4d662daa9","analyzedAt":"2026-09-14T10:12:48.479Z","contentChangedAt":"2026-09-14T10:12:48.479Z","schemaVersion":2},"datasetVersion":"2026-09-22T01:17:13.364Z"}