dotnet/wpf · error · ArgumentException
SR.Format(SR.VisualTreeRootIsFrameworkElement…
Error message
SR.Format(SR.VisualTreeRootIsFrameworkElement, nameof(FrameworkElement), templateRoot.Type.Name)
What it means
ValidateVisualTree throws ArgumentException (SR.VisualTreeRootIsFrameworkElement) when a template's visual tree root (a FrameworkTemplate built from a VisualTree or factory) is a FrameworkContentElement-derived type. Template visual roots must be visual elements (FrameworkElement), not content elements such as Run or Paragraph.
Solutions
- Wrap the content element in a visual host such as TextBlock or a Control-derived element so the template root is a FrameworkElement.
- Replace the Run root with TextBlock (which hosts Run content) in the template.
- For document content, use FlowDocumentScrollViewer or similar FrameworkElement containers as the template root.
Example fix
// before var f = new FrameworkElementFactory(typeof(Run)); // FrameworkContentElement root template.VisualTree = f; // throws on validation // after var f = new FrameworkElementFactory(typeof(TextBlock)); f.SetValue(TextBlock.TextProperty, "Hello"); template.VisualTree = f;
Defensive patterns
Strategy: validation
Validate before calling
if (typeof(FrameworkContentElement).IsAssignableFrom(factory.Type))
throw new ArgumentException("Template root must be a FrameworkElement, not " + factory.Type.Name); Type guard
static bool IsVisualRoot(FrameworkElementFactory f) => f?.Type != null && typeof(FrameworkElement).IsAssignableFrom(f.Type);
Prevention
- Always root templates in FrameworkElement-derived types (Grid, TextBlock, Border, Control).
- Host content elements (Run, Paragraph) inside TextBlock or a viewer control.
When it happens
Trigger: Setting ControlTemplate/FrameworkTemplate.VisualTree to a factory whose Type derives from FrameworkContentElement (e.g. System.Windows.Documents.Run); building a template in code whose root node is a content element.
Common situations: Programmatically constructing templates with FrameworkElementFactory rooted at text/document elements; XAML templates whose outermost tag is a FlowDocument content element; refactoring code-generated templates to use Runs for text.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- SR.TemplateFindNameInInvalidElement
- VisualTree of ItemsPanelTemplate must be a single element.
- ' ' is not a Visual or Visual3D.
- inverse ? SR.Visual_NotADescendant : SR.Visual_NotAnAncestor
- Page can have only Window or Frame as parent.
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/76fe1e85746f1374.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/FrameworkTemplate.cs:374
#region NonPublicMethods
// ===========================================================================
// Validation methods
// ===========================================================================
// Validate against the following rules
// 1. The VisualTree's root must be a FrameworkElement.
private void ValidateVisualTree(FrameworkElementFactory templateRoot)
{
// The VisualTree's root must be a FrameworkElement.
if (templateRoot != null &&
typeof(FrameworkContentElement).IsAssignableFrom(templateRoot.Type))
{
throw new ArgumentException(SR.Format(SR.VisualTreeRootIsFrameworkElement, nameof(FrameworkElement), templateRoot.Type.Name));
}
}
// ===========================================================================
// These methods are invoked when a Template is being sealed
// ===========================================================================
#region Seal
internal virtual void ProcessTemplateBeforeSeal()
{
}
/// <summary>
/// Seal this FrameworkTemplate
/// </summary>View on GitHub (pinned to 81131a70a4)