dotnet/maui · error · InvalidOperationException
Cannot assign a native control without an Element; Renderer
Error message
Cannot assign a native control without an Element; Renderer unbound and/or disposed. Please consult Microsoft.Maui.Controls.Compatibility renderers for reference implementation of OnElementChanged.
What it means
VisualElementRenderer.SetControl (called via SetNativeControl) throws InvalidOperationException when assigning a native control while Element is null. This indicates the renderer is unbound — either disposed, or SetNativeControl was called before SetElement in the lifecycle. The renderer needs an Element to wire up platform-state consistency and event handlers.
Source
Thrown at src/Compatibility/Core/src/Windows/VisualElementRenderer.cs:429
oldControl.Loaded -= OnControlLoaded;
oldControl.GotFocus -= OnControlGotFocus;
oldControl.LostFocus -= OnControlLostFocus;
}
UpdateTracker();
if (control == null)
{
_controlChanged?.Invoke(this, EventArgs.Empty);
return;
}
Control.HorizontalAlignment = Microsoft.UI.Xaml.HorizontalAlignment.Stretch;
Control.VerticalAlignment = Microsoft.UI.Xaml.VerticalAlignment.Stretch;
if (Element == null)
throw new InvalidOperationException(
"Cannot assign a native control without an Element; Renderer unbound and/or disposed. " +
"Please consult Microsoft.Maui.Controls.Compatibility renderers for reference implementation of OnElementChanged.");
Element.IsPlatformStateConsistent = false;
control.Loaded += OnControlLoaded;
control.GotFocus += OnControlGotFocus;
control.LostFocus += OnControlLostFocus;
#pragma warning disable RS0030 // Do not use banned APIs; Panel.Children is banned for performance reasons.
Children.Add(control);
#pragma warning restore RS0030 // Do not use banned APIs
UpdateBackgroundColor();
UpdateBackground();
if (Element != null && !string.IsNullOrEmpty(Element.AutomationId))
SetAutomationId(Element.AutomationId);View on GitHub (pinned to f377ff1c5e)
Solutions
- Guard SetNativeControl: if (Element != null) { SetNativeControl(control); }
- Ensure SetNativeControl is called after SetElement — typically inside OnElementChanged after base.SetElement
- Check _disposed flag before calling SetNativeControl in async callbacks
- Avoid calling SetNativeControl from constructors; defer to OnElementChanged
Example fix
// before
protected override void OnElementChanged(ElementChangedEventArgs<MyView> e)
{
base.OnElementChanged(e);
SetNativeControl(new MyNativeControl()); // may throw if Element is null after dispose
}
// after
protected override void OnElementChanged(ElementChangedEventArgs<MyView> e)
{
base.OnElementChanged(e);
if (e.NewElement != null && !_disposed && Control == null)
SetNativeControl(new MyNativeControl());
} Defensive patterns
Strategy: validation
Validate before calling
// Before calling SetNativeControl, verify Element is bound
if (Element == null || _disposed)
return;
SetNativeControl(nativeControl); Try / catch
try
{
SetNativeControl(control);
}
catch (InvalidOperationException ex) when (ex.Message.Contains("without an Element"))
{
// Renderer was disposed — abort control assignment
// This is a lifecycle race; the renderer should not be reused
} Prevention
- Always call SetNativeControl inside OnElementChanged after base.SetElement assigns Element
- Guard with if (Element != null && !_disposed) before SetNativeControl
- Never call SetNativeControl from constructors or async continuations without checking Element
- Implement proper disposal flags to prevent reuse of disposed renderers
When it happens
Trigger: Calling SetNativeControl after Dispose has nulled the Element; renderer reuse after disposal; calling SetNativeControl in OnElementChanged before Element is assigned; async race condition where Dispose runs between element binding and control assignment (common in cell recycling).
Common situations: Custom renderer calling SetNativeControl in the constructor instead of OnElementChanged; ListView/CollectionView cell recycling reuses disposed renderers; rapid page navigation triggers disposal during async control setup.
Related errors
- Could not find or create a renderer for {visualElement}
- Element must be a TabbedPage
- self
- renderer
- Renderer's container element must be a Panel
AI-assisted analysis of dotnet/maui@f377ff1c5e (2026-08-13).
Data as JSON: /api/errors/479045258d4d9b08.
Report an issue: GitHub.