dotnet/wpf · error · ArgumentException

SR.Format(SR.Invalid_IInputElement, element.GetType())

Error message

SR.Format(SR.Invalid_IInputElement, element.GetType())

What it means

TouchDevice.Capture accepts only elements that implement WPF's IInputElement contract as concrete UIElement, ContentElement, or UIElement3D instances. Before capturing, CastInputElement tries to cast the argument to those three concrete types; if the element is non-null yet none of the casts succeed, the device cannot route touch events to it, so an ArgumentException naming the 'element' parameter is thrown. This guards the invariant that captured objects participate in WPF input hit-testing and event routing.

Solutions

  1. Pass a real UIElement (or ContentElement/UIElement3D) instance to TouchDevice.Capture — typically the element that received the TouchDown event (e.g. args.Source or args.OriginalSource as UIElement).
  2. If you have a custom element class, derive it from UIElement rather than implementing IInputElement manually.
  3. Before calling, verify the target with the same check the API performs: element is null or is UIElement/ContentElement/UIElement3D.

Example fix

// before
object source = e.OriginalSource;
touchDevice.Capture(source); // ArgumentException if source is not a supported element

// after
var element = e.OriginalSource as UIElement;
touchDevice.Capture(element); // null means 'release capture'; valid UIElement means capture
Defensive patterns

Strategy: type-guard

Validate before calling

bool canCapture(object element) =>
    element == null || element is UIElement || element is ContentElement || element is UIElement3D;

Type guard

bool IsInputElement(object o, out IInputElement input) =>
    (input = o as UIElement ?? (IInputElement)(o as ContentElement) ?? (o as UIElement3D)) != null || o == null;

Try / catch

try { touchDevice.Capture(element); }
catch (ArgumentException ex) when (ex.ParamName == "element")
{
    // fall back to capturing the original source element
    touchDevice.Capture(e.OriginalSource as UIElement);
}

Prevention

When it happens

Trigger: Calling touchDevice.Capture(obj) where obj is non-null but is not a UIElement, ContentElement, or UIElement3D — e.g. passing a raw DependencyObject, a custom control that implements IInputElement but does not derive from the three supported classes, a Window content proxy, or a mistakenly wrapped/partial-class instance.

Common situations: Custom framework code implementing IInputElement directly instead of subclassing UIElement; passing view-model or wrapper objects to Capture; interop scenarios where a foreign element type from another framework is passed; typos that pass the wrong variable (e.g. a DataContext instead of the visual element).

Understand the failure class

Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.

Related errors


AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14). Data as JSON: /api/errors/c5cf0b04d8a22ef4. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Input/TouchDevice.cs:331

        {
            VerifyAccess();

            // If the element is null or captureMode is None, ensure
            // that the other parameter is consistent.
            if ((element == null) || (captureMode == CaptureMode.None))
            {
                element = null;
                captureMode = CaptureMode.None;
            }

            UIElement uiElement;
            ContentElement contentElement;
            UIElement3D uiElement3D;
            CastInputElement(element, out uiElement, out contentElement, out uiElement3D);

            if ((element != null) && (uiElement == null) && (contentElement == null) && (uiElement3D == null))
            {
                throw new ArgumentException(SR.Format(SR.Invalid_IInputElement, element.GetType()), nameof(element));
            }

            if (_captured != element)
            {
                // Ensure that the new element is visible and enabled
                if ((element == null) ||
                    (((uiElement != null) && uiElement.IsVisible && uiElement.IsEnabled) ||
                    ((contentElement != null) && contentElement.IsEnabled) ||
                    ((uiElement3D != null) && uiElement3D.IsVisible && uiElement3D.IsEnabled)))
                {
                    IInputElement oldCapture = _captured;
                    _captured = element;
                    _captureMode = captureMode;

                    UIElement oldUIElement;
                    ContentElement oldContentElement;
                    UIElement3D oldUIElement3D;
                    CastInputElement(oldCapture, out oldUIElement, out oldContentElement, out oldUIElement3D);

View on GitHub (pinned to 81131a70a4)