dotnet/wpf · error · InvalidOperationException

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

Error message

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

What it means

WispLogic.ChangeStylusOver (WispLogic.cs:2204) throws InvalidOperationException(SR.Invalid_IInputElement) when the element currently under the stylus (_stylusOver) is neither a UIElement, ContentElement, nor UIElement3D. The WPF stylus input system only tracks those three input element types, so it fails fast instead of silently skipping hit-testable-event bookkeeping. It indicates an IInputElement reached internal stylus state that the stylus stack cannot handle.

Solutions

  1. Ensure the element under the stylus derives from UIElement, ContentElement, or UIElement3D rather than implementing IInputElement directly.
  2. Audit custom hit-test / input code that may assign a non-standard IInputElement to the stylus over-path.
  3. Reproduce under debugger and inspect _stylusOver.GetType() to identify the foreign element type and its creator.

Example fix

// before
class MyElement : FrameworkContentElement, IInputElement { } // ok, but a raw IInputElement is not
// after
class MyElement : UIElement { } // derive from a supported input element base
Defensive patterns

Strategy: type-guard

Validate before calling

static bool CanBeStylusOver(object e) => e is UIElement || e is ContentElement || e is UIElement3D;

Type guard

static bool IsValidInputElement(IInputElement e) => e is UIElement || e is ContentElement || e is UIElement3D;

Try / catch

try { /* stylus over handling */ } catch (InvalidOperationException ex) when (ex.Message.Contains("IInputElement")) { /* log and fall back to mouse handling */ }

Prevention

When it happens

Trigger: ChangeStylusOver is called (e.g. from stylus move/enter processing) with _stylusOver set to an object that passed IInputElement hit testing but fails the is-UIElement/is-ContentElement/is-UIElement3D pattern match — i.e. a custom IInputElement implementation feeding the stylus over-state.

Common situations: Custom control frameworks implementing IInputElement directly instead of deriving from UIElement/ContentElement; third-party presentation surfaces injecting foreign elements into the input tree; internal state corruption after re-templating or visual-tree mutations during stylus input.

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/bc857bc65e5553b1. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Input/Stylus/Wisp/WispLogic.cs:2204

                    }
                    else if (o is ContentElement ce)
                    {
                        ce.IsEnabledChanged += _overIsEnabledChangedEventHandler;

                        // NOTE: there are no IsVisible or IsHitTestVisible properties for ContentElements.
                        //
                        // ce.IsVisibleChanged += _overIsVisibleChangedEventHandler;
                        // ce.IsHitTestVisibleChanged += _overIsHitTestVisibleChangedEventHandler;
                    }
                    else if (o is UIElement3D uie3D)
                    {
                        uie3D.IsEnabledChanged += _overIsEnabledChangedEventHandler;
                        uie3D.IsVisibleChanged += _overIsVisibleChangedEventHandler;
                        uie3D.IsHitTestVisibleChanged += _overIsHitTestVisibleChangedEventHandler;
                    }
                    else
                    {
                        throw new InvalidOperationException(SR.Format(SR.Invalid_IInputElement, _stylusOver.GetType())); 
                    }
                }

                // Oddly enough, update the IsStylusOver property first.  This is
                // so any callbacks will see the more-common IsStylusOver property
                // set correctly.
                UIElement.StylusOverProperty.OnOriginValueChanged(oldOver as DependencyObject, _stylusOver as DependencyObject, ref _stylusOverTreeState);

                // Invalidate the IsStylusDirectlyOver property.
                if (oldOver != null)
                {
                    o = oldOver as DependencyObject;
                    o.SetValue(UIElement.IsStylusDirectlyOverPropertyKey, false); // Same property for ContentElements
                }
                if (_stylusOver != null)
                {
                    o = _stylusOver as DependencyObject;
                    o.SetValue(UIElement.IsStylusDirectlyOverPropertyKey, true); // Same property for ContentElements

View on GitHub (pinned to 81131a70a4)