dotnet/wpf · error · InvalidOperationException
SR.Format(SR.ItemsPanelNotAPanel, templateHolder.RootType)
Error message
SR.Format(SR.ItemsPanelNotAPanel, templateHolder.RootType)
What it means
The root element of an ItemsPanelTemplate's visual tree must derive from System.Windows.Controls.Panel. During ProcessTemplateBeforeSeal, if the template content's root type is null or cannot be assigned to Panel, WPF throws InvalidOperationException naming the offending root type.
Solutions
- Make the root element of the ItemsPanelTemplate a Panel (StackPanel, VirtualizingStackPanel, WrapPanel, UniformGrid, Grid, etc.).
- If decoration is needed, move it out of the ItemsPanelTemplate into the ItemTemplate or container style.
- Fix malformed XAML so the template body parses to a concrete root type.
Example fix
// before <ItemsPanelTemplate> <Border><StackPanel/></Border> </ItemsPanelTemplate> // after <ItemsPanelTemplate> <StackPanel/> </ItemsPanelTemplate>
Defensive patterns
Strategy: validation
Validate before calling
bool IsPanelRoot(ItemsPanelTemplate t) =>
(t?.VisualTree?.GetType() ?? t?.Template?.RootType?.UnderlyingType)?.IsSubclassOf(typeof(System.Windows.Controls.Panel)) == true; Type guard
bool IsPanel(Type t) => t != null && typeof(System.Windows.Controls.Panel).IsAssignableFrom(t);
Try / catch
try { itemsControl.ItemsPanel = (ItemsPanelTemplate)Resources["ItemsPanel"]; } catch (InvalidOperationException ex) when (ex.Message.Contains("panel")) { itemsControl.ItemsPanel = new ItemsPanelTemplate { VisualTree = new FrameworkElementFactory(typeof(StackPanel)) }; } Prevention
- Always make the ItemsPanelTemplate root a Panel-derived element.
- Do not wrap the panel in Border/Decorator inside ItemsPanelTemplate.
- Use VirtualizingStackPanel as the root for large virtualized lists.
When it happens
Trigger: Placing a non-Panel element (e.g. <Grid> is fine, but <Border>, <TextBlock>, <ContentPresenter>, or a Control) as the direct child of ItemsPanelTemplate; an empty or malformed template body leaving RootType null.
Common situations: Copy-pasting a DataTemplate's content (often a Border/TextBlock) into ItemsPanelTemplate; typos or wrong xmlns producing a null root type; wrapping the panel in a decorator.
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.Format(SR.ItemsPanelNotAPanel, root.Type)
- SR.TemplateNotTargetType
- A panel with IsItemsHost="true" is not nested in an…
- Animation_ChildMustBeKeyFrame
- Animation_ChildMustBeKeyFrame
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/9af996a9f16885a7.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/ItemsPanelTemplate.cs:117
// a. root element is a Panel
// 2. Set IsItemsHost = true
//
internal override void ProcessTemplateBeforeSeal()
{
FrameworkElementFactory root;
if( HasContent )
{
// This is a Baml-style template
// Validate the root type (it must be a Panel)
TemplateContent templateHolder = Template as TemplateContent;
System.Xaml.XamlType panelType = templateHolder.SchemaContext.GetXamlType(typeof(Panel));
if (templateHolder.RootType == null || !templateHolder.RootType.CanAssignTo(panelType))
{
throw new InvalidOperationException(SR.Format(SR.ItemsPanelNotAPanel, templateHolder.RootType));
}
}
else if ((root = this.VisualTree) != null)
{
// This is a FEF-style template
if (!typeof(Panel).IsAssignableFrom(root.Type))
throw new InvalidOperationException(SR.Format(SR.ItemsPanelNotAPanel, root.Type));
root.SetValue(Panel.IsItemsHostProperty, true);
}
}
#endregion Internal Methods
#region Protected Methods
View on GitHub (pinned to 81131a70a4)