dotnet/wpf · error · InvalidOperationException

SR.Format(SR.CannotChangeAfterSealed…

Error message

SR.Format(SR.CannotChangeAfterSealed, "FrameworkElementFactory")

What it means

FrameworkElementFactory becomes sealed (immutable) once it is used to create a template instance. Attempting to set the Type property afterwards throws InvalidOperationException(SR.CannotChangeAfterSealed, "FrameworkElementFactory"). All configuration must happen before the factory is compiled into a template and instantiated.

Solutions

  1. Create a new FrameworkElementFactory for each template (re)definition instead of reusing a sealed one
  2. Perform all factory configuration (Type, properties, children) immediately after construction, before attaching to a template
  3. Cache the DataTemplate, not the mutable factory, and rebuild factories when configuration changes
  4. Check factory.IsSealed before mutating to fail fast in debug builds

Example fix

// before
static FrameworkElementFactory factory = Build();
// later
factory.FactoryType = typeof(Button); // throws when sealed
// after
var factory = new FrameworkElementFactory(typeof(Button)); // fresh instance per template
template.VisualTree = factory;
Defensive patterns

Strategy: validation

Validate before calling

if (factory.IsSealed) throw new InvalidOperationException("FrameworkElementFactory is sealed; create a new one");

Type guard

bool CanMutateFactory(FrameworkElementFactory f) => !f.IsSealed;

Try / catch

try { factory.FactoryType = typeof(Button); }
catch (InvalidOperationException) { factory = new FrameworkElementFactory(typeof(Button)); }

Prevention

When it happens

Trigger: Setting FactoryType (or other properties) on a FrameworkElementFactory after a template that uses it has been sealed — i.e. after the template was applied/compiled and instances created.

Common situations: Mutating a shared factory cached in a static field after first use; changing factory Type in code after assigning it to a DataTemplate/ControlTemplate; hot-swapping template definitions at runtime without creating fresh factories.

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


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

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/FrameworkElementFactory.cs:72

        /// <param name="name">Style identifier</param>
        public FrameworkElementFactory(Type type, string name)
        {
            Type = type;
            Name = name;
        }


        /// <summary>
        ///     Type of object that the factory will produce
        /// </summary>
        public Type Type
        {
            get { return _type; }
            set
            {
                if (_sealed)
                {
                    throw new InvalidOperationException(SR.Format(SR.CannotChangeAfterSealed, "FrameworkElementFactory"));
                }

                if (_text != null)
                {
                    throw new InvalidOperationException(SR.FrameworkElementFactoryCannotAddText);
                }

                if ( value != null ) // We allow null up until Seal
                {
                    // If non-null, must be derived from one of the supported types
                    if (!typeof(FrameworkElement).IsAssignableFrom(value) &&
                        !typeof(FrameworkContentElement).IsAssignableFrom(value) &&
                        !typeof(Visual3D).IsAssignableFrom(value))
                    {
                        throw new ArgumentException(SR.Format(SR.MustBeFrameworkOr3DDerived, value.Name));
                    }
                }

View on GitHub (pinned to 81131a70a4)