dotnet/wpf · error · InvalidOperationException
SR.Format(SR.CannotChangeAfterSealed, "TriggerAction")
Error message
SR.Format(SR.CannotChangeAfterSealed, "TriggerAction")
What it means
TriggerAction.CheckSealed() throws InvalidOperationException (CannotChangeAfterSealed, 'TriggerAction') when any mutation is attempted on a TriggerAction after it has been sealed. Sealed objects are frozen into an immutable state once the owning Style/Template is applied, so later edits are rejected.
Solutions
- Clone the action (or define a new Style) before modifying, then re-apply the style
- Create styles in XAML or before first use; avoid runtime mutation
- Check the action's IsSealed property before mutating
Example fix
// before
style.Triggers[0].Actions[0].Parameter = newValue; // throws if sealed
// after
var newStyle = new Style { BasedOn = style };
newAction = new TriggerAction { Parameter = newValue };
newStyle.Triggers[0].Actions.Add(newAction);
control.Style = newStyle; Defensive patterns
Strategy: validation
Validate before calling
if (action.IsSealed) throw new InvalidOperationException("Action sealed; rebuild style before mutating.");
action.Parameter = newValue; Type guard
static bool IsMutable(TriggerAction a) => a != null && !a.IsSealed;
Try / catch
try { action.Parameter = v; }
catch (InvalidOperationException ex) when (ex.Message.Contains("TriggerAction")) { /* rebuild style */ } Prevention
- Configure triggers only during style construction
- Clone styles before runtime edits
- Avoid mutating shared/global styles after Window load
When it happens
Trigger: Mutating properties of a TriggerAction (or its contents) after the containing Style/Template was applied to an element and thus sealed.
Common situations: Modifying a shared style's triggers at runtime after controls using it are rendered; changing EventSetter/InvokeCommandAction parameters from event handlers or timers.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- SR.Format(SR.CannotChangeAfterSealed, "trigger")
- SR.Format(SR.CannotChangeAfterSealed…
- SR.TriggerActionAlreadySealed
- CannotChangeAfterSealed
- CannotChangeAfterSealed
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/02c466ebc7fd797b.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/TriggerAction.cs:114
/// validation checks to see if all parameters make sense.
/// </summary>
internal override void Seal()
{
if( IsSealed )
{
throw new InvalidOperationException(SR.TriggerActionAlreadySealed);
}
base.Seal();
}
/// <summary>
/// Checks sealed status and throws exception if object is sealed
/// </summary>
internal void CheckSealed()
{
if( IsSealed )
{
throw new InvalidOperationException(SR.Format(SR.CannotChangeAfterSealed, "TriggerAction"));
}
}
// Define the DO's inheritance context
internal override DependencyObject InheritanceContext
{
get { return _inheritanceContext; }
}
// Receive a new inheritance context (this will be a FE/FCE)
internal override void AddInheritanceContext(DependencyObject context, DependencyProperty property)
{
InheritanceContextHelper.AddInheritanceContext(context,
this,
ref _hasMultipleInheritanceContexts,
ref _inheritanceContext);
}View on GitHub (pinned to 81131a70a4)