dotnet/wpf · error · InvalidOperationException
SR.FrameworkElementFactoryCannotAddText
Error message
SR.FrameworkElementFactoryCannotAddText
What it means
FrameworkElementFactory.Type setter throws this InvalidOperationException when the factory already holds literal text content (_text != null) and you try to assign a Type. A FrameworkElementFactory can describe either text content or an element type, never both. WPF throws early so the invalid template tree is never built.
Solutions
- Decide on one content mode: either set Text or set Type, not both, on the same factory instance.
- If both are needed, create a separate FrameworkElementFactory for the text and attach it via AppendChild to the typed parent factory.
- Check factory.Text is null before assigning Type (guard with an if or clear Text first by setting it to null before Seal).
Example fix
// before var fef = new FrameworkElementFactory(); fef.Text = "hello"; fef.Type = typeof(TextBlock); // throws // after var fef = new FrameworkElementFactory(typeof(TextBlock)); fef.SetValue(TextBlock.TextProperty, "hello");
Defensive patterns
Strategy: validation
Validate before calling
if (factory.Text != null)
throw new InvalidOperationException("Cannot set Type: factory already has Text content.");
factory.Type = typeof(TextBlock); Type guard
bool CanSetType(FrameworkElementFactory f) => f.Text is null;
Prevention
- Pick text OR type per factory at construction time and enforce it in your builder API.
- Use constructor overload new FrameworkElementFactory(typeof(T)) to make the mode explicit.
- Never expose raw FrameworkElementFactory mutation to callers; wrap in a builder that tracks mode.
When it happens
Trigger: Calling factory.Text = "some text" (or the internal text path) and then assigning factory.Type = typeof(...) on the same FrameworkElementFactory instance.
Common situations: Building a DataTemplate/ControlTemplate programmatically where one code path sets Text and a later refactoring or shared helper also sets Type on the same factory; merging template-building code from two branches.
Related errors
- IAmbientProvider
- IXamlSchemaContextProvider
- SR.Format(SR.MustBeFrameworkOr3DDerived, value.Name)
- SR.FrameworkElementFactoryAlreadyParented
- SR.NameNotEmptyString
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/f1b69f91a00d2c7d.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/FrameworkElementFactory.cs:77
}
/// <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));
}
}
// It is possible that _type is null when a FEF is created for text content within a tag
_type = value;
// If this is a KnownType in the BamlSchemaContext, then there is a faster way to create
// an instance of that type than using Activator.CreateInstance. So in that caseView on GitHub (pinned to 81131a70a4)