dotnet/maui · error · ArgumentException
Element must be of type Button.
Error message
Element must be of type Button.
What it means
MaterialButtonRenderer renders Material Design Buttons on Android. SetElement casts the incoming VisualElement to Button and throws ArgumentException if the element is not a Button. This is a hard contract: the renderer's layout, styling, and event wiring all assume a Button element.
Source
Thrown at src/Compatibility/Material/src/Android/MaterialButtonRenderer.cs:418
AColor IBorderVisualElementRenderer.ShadowColor => ShadowColor;
bool IBorderVisualElementRenderer.UseDefaultPadding() => OnThisPlatform().UseDefaultPadding();
bool IBorderVisualElementRenderer.UseDefaultShadow() => OnThisPlatform().UseDefaultShadow();
bool IBorderVisualElementRenderer.IsShadowEnabled() => true;
VisualElement IBorderVisualElementRenderer.Element => Element;
AView IBorderVisualElementRenderer.View => this;
// IVisualElementRenderer
VisualElement IVisualElementRenderer.Element => Element;
VisualElementTracker IVisualElementRenderer.Tracker => _tracker;
AView IVisualElementRenderer.View => this;
SizeRequest IVisualElementRenderer.GetDesiredSize(int widthConstraint, int heightConstraint)
{
return _buttonLayoutManager.GetDesiredSize(widthConstraint, heightConstraint);
}
void IVisualElementRenderer.SetElement(VisualElement element) =>
Element = (element as Button) ?? throw new ArgumentException("Element must be of type Button.");
void IVisualElementRenderer.SetLabelFor(int? id)
{
if (_defaultLabelFor == null)
_defaultLabelFor = ViewCompat.GetLabelFor(this);
ViewCompat.SetLabelFor(this, (int)(id ?? _defaultLabelFor));
}
void IVisualElementRenderer.UpdateLayout() =>
_tracker?.UpdateLayout();
// IViewRenderer
void IViewRenderer.MeasureExactly() =>
ViewRenderer.MeasureExactly(this, Element, Context);
// ITabStop
AView ITabStop.TabStop => this;
View on GitHub (pinned to f377ff1c5e)
Solutions
- Verify ExportRenderer maps Button (not a custom type) to MaterialButtonRenderer.
- Ensure custom controls intended for this renderer derive from Button.
- Audit the renderer registrar for duplicate Button registrations across assemblies.
- Confirm `VisualMarker.Material` is applied to actual Button instances.
Example fix
// before [assembly: ExportRenderer(typeof(MyCustomLabel), typeof(MaterialButtonRenderer))] // after [assembly: ExportRenderer(typeof(Button), typeof(MaterialButtonRenderer))]
Defensive patterns
Strategy: type-guard
Validate before calling
if (element is not Button)
throw new InvalidOperationException($"Expected Button, got {element?.GetType().Name}");
renderer.SetElement(element); Type guard
static bool IsButton(VisualElement? element) => element is Button;
Prevention
- Verify ExportRenderer maps Button to MaterialButtonRenderer in every platform project.
- Ensure custom button controls inherit from Button.
- Remove stale renderer registrations after refactoring element hierarchies.
When it happens
Trigger: The renderer registry dispatches a non-Button element to MaterialButtonRenderer. Occurs with incorrect ExportRenderer mappings or when a custom element type not deriving from Button is paired with this renderer.
Common situations: Misconfigured ExportRenderer attributes pairing a non-Button element with MaterialButtonRenderer. Stale registrations left after refactoring controls. Third-party libraries registering conflicting Button renderers.
Related errors
- {element?.GetType().FullName} is not compatible. element mus
- Element must be of type Frame.
- Element must be of type ProgressBar.
- Element must be of type Slider.
- {nameof(element)} must be of type {nameof(Button)}
AI-assisted analysis of dotnet/maui@f377ff1c5e (2026-08-13).
Data as JSON: /api/errors/df2a0a329abcbe2d.
Report an issue: GitHub.