dotnet/wpf · error · InvalidOperationException

Failed to set enabled gestures.

Error message

Failed to set enabled gestures.

What it means

Gesture recognition is performed through the native Tablet PC ink recognizer via a context handle (SetEnabledGestures P/Invoke). When the native call returns a failing HRESULT, the wrapper throws InvalidOperationException deliberately withholding COM error details because none are useful to surface. It means the native recognizer refused to update its enabled-gesture set.

Solutions

  1. Verify the Tablet PC / ink recognition components are installed and functional on the target machine
  2. Ensure the GestureRecognizer (and its native context) is still alive and not disposed when setting EnabledGestures
  3. Catch InvalidOperationException around the EnabledGestures assignment and degrade gracefully (disable gesture features)
  4. Re-create the GestureRecognizer instance to get a fresh native context and retry once

Example fix

// before
recognizer.EnabledGestures = new[] { ApplicationGesture.Down };
// after
try { recognizer.EnabledGestures = new[] { ApplicationGesture.Down }; }
catch (InvalidOperationException) { /* ink engine unavailable; fall back to no gesture recognition */ }
Defensive patterns

Strategy: try-catch

Validate before calling

if (recognizer == null) throw new InvalidOperationException("Recognizer not initialized");
// ensure ink platform present before use
bool inkAvailable = OperatingSystem.IsWindows();

Type guard

static bool HasLiveContext(GestureRecognizer r) => r != null && !r.IsDisposed;

Try / catch

try { recognizer.EnabledGestures = gestures; }
catch (InvalidOperationException ex) { logger.LogWarning(ex, "Gesture enable failed"); gestureSupport = false; }

Prevention

When it happens

Trigger: Calling GestureRecognizer.EnabledGestures setter (SetEnabledGestures) after the native recognizer context handle is invalid, disposed, or when the underlying ink recognition engine (Tablet PC platform / ISF components) is unavailable on the machine.

Common situations: Running on machines or in environments (e.g. non-Windows, server SKUs, containers) without the Tablet PC ink recognition service; using a GestureRecognizer whose native context has been disposed or failed to initialize.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Ink/GestureRecognizer/NativeRecognizer.cs:103

        /// <summary>
        /// Set the enabled gestures
        /// </summary>
        /// <param name="applicationGestures"></param>
        internal ApplicationGesture[] SetEnabledGestures(IEnumerable<ApplicationGesture> applicationGestures)
        {
            ObjectDisposedException.ThrowIf(_disposed, typeof(NativeRecognizer));

            //validate and get an array out
            ApplicationGesture[] enabledGestures =
                GetApplicationGestureArrayAndVerify(applicationGestures);

            // Set enabled Gestures.
            int hr = SetEnabledGestures(_hContext, enabledGestures);
            if (HRESULT.Failed(hr))
            {
                //don't throw a com exception here, we don't need to pass out any details
                throw new InvalidOperationException(SR.UnspecifiedSetEnabledGesturesException);
            }

            return enabledGestures;
        }

        /// <summary>
        /// Recognize the strokes.
        /// </summary>
        /// <param name="strokes"></param>
        /// <returns></returns>
        internal GestureRecognitionResult[] Recognize(StrokeCollection strokes)
        {
            ObjectDisposedException.ThrowIf(_disposed, typeof(NativeRecognizer));

            //
            // note that we validate this argument from GestureRecognizer 
            // but since this is marked TAS, we want to do it here as well
            //

View on GitHub (pinned to 81131a70a4)