dotnet/wpf · error · InvalidOperationException
SR.Format(SR.CannotChangeAfterSealed, "Trigger")
Error message
SR.Format(SR.CannotChangeAfterSealed, "Trigger")
What it means
Trigger.Property has a setter that throws InvalidOperationException once the Trigger has been sealed (attached to a sealed Style/template). WPF seals triggers when the owning style is sealed so shared style state cannot be mutated. This protects thread-safety and consistency of sealed styles.
Solutions
- Create a new Trigger instance and set Property on it, then rebuild/replace the style before applying it.
- Build the complete Trigger (Property, Value, Setters) before adding it to Style.Triggers.
- If the style must change at runtime, construct a new Style with the modified trigger and assign it.
Example fix
// before
sealedTrigger.Property = UIElement.OpacityProperty; // throws
// after
var trigger = new Trigger { Property = UIElement.OpacityProperty, Value = 0.5 };
style.Triggers.Add(trigger); Defensive patterns
Strategy: validation
Validate before calling
if (trigger.IsSealed) throw new InvalidOperationException("Create a new Trigger instead of mutating a sealed one"); Type guard
static bool IsEditable(Trigger t) => t != null && !t.IsSealed;
Try / catch
try { trigger.Property = p; }
catch (InvalidOperationException) { var replacement = new Trigger { Property = p, Value = trigger.Value }; style.Triggers[style.Triggers.IndexOf(trigger)] = replacement; } Prevention
- Fully configure Trigger (Property/Value/Setters) before adding to a style
- Treat sealed styles as immutable; build a new Style for runtime changes
- Never cache and later mutate shared Trigger instances
When it happens
Trigger: Setting trigger.Property on a Trigger instance that was already used in a Style whose resources were sealed, e.g. modifying a Style.Triggers entry after Style.Seal() or after the style is applied/frozen.
Common situations: Mutating a style's triggers at runtime after the style was applied to controls; reusing one Trigger object across styles and editing it later.
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.InvalidPropertyValue, _value, _property.Name)
- Animation_Invalid_DefaultValue
- Cannot remove signature from read-only file.
- Image_EncoderNoColorContext
- Image_EncoderNoGlobalMetadata
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/0be56f20e3d92d29.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Trigger.cs:39
[Ambient]
[Localizability(LocalizationCategory.None, Modifiability = Modifiability.Unmodifiable, Readability = Readability.Unreadable)] // Not localizable by-default
public DependencyProperty Property
{
get
{
// Verify Context Access
VerifyAccess();
return _property;
}
set
{
// Verify Context Access
VerifyAccess();
if (IsSealed)
{
throw new InvalidOperationException(SR.Format(SR.CannotChangeAfterSealed, "Trigger"));
}
_property = value;
}
}
/// <summary>
/// Value of the condition (equality check)
/// </summary>
[DependsOn("Property")]
[DependsOn("SourceName")]
[Localizability(LocalizationCategory.None, Readability = Readability.Unreadable)] // Not localizable by-default
[TypeConverter(typeof(SetterTriggerConditionValueConverter))]
public object Value
{
get
{
// Verify Context AccessView on GitHub (pinned to 81131a70a4)