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

  1. Wrap the content element in a visual host such as TextBlock or a Control-derived element so the template root is a FrameworkElement.
  2. Replace the Run root with TextBlock (which hosts Run content) in the template.
  3. 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

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


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)