dotnet/wpf · error · InvalidOperationException

Microsoft.Windows.Controls.SR.ElementNotKeyTipScope

Error message

Microsoft.Windows.Controls.SR.ElementNotKeyTipScope

What it means

KeyTipService handles focus-scope changes while key tips are active. If the pending focus target (TargetKeyTipScope) is not itself a registered key tip scope (KeyTipService.GetIsKeyTipScope returns false) and is not the current global scope, the service throws InvalidOperationException (SR.ElementNotKeyTipScope) because key tip navigation can only move focus into designated key tip scopes.

Solutions

  1. Mark the target element as a key tip scope: KeyTipService.SetIsKeyTipScope(targetElement, true)
  2. Ensure focus changes during key tip mode target either a registered key tip scope or the current global scope
  3. Defer the focus change until after key tips are dismissed (e.g. in the Dispatcher at background priority after KeyTipService exits)
  4. Catch InvalidOperationException and fall back to focusing the current global scope

Example fix

// before
myPanel.Focus(); // not a registered key tip scope -> throws during key tip navigation
// after
KeyTipService.SetIsKeyTipScope(myPanel, true);
myPanel.Focus();
Defensive patterns

Strategy: validation

Validate before calling

if (KeyTipService.GetIsKeyTipScope(target) || target == /* current global scope */) target.Focus();

Type guard

bool IsKeyTipScopeTarget(DependencyObject target) => KeyTipService.GetIsKeyTipScope(target);

Try / catch

try { target.Focus(); }
catch (InvalidOperationException) { /* target is not a key tip scope; focus global scope instead */ }

Prevention

When it happens

Trigger: During key tip navigation, an element sets Keyboard focus (or TargetKeyTipScope) to a DependencyObject that was never marked as a key tip scope via KeyTipService.SetIsKeyTipScope(element, true), while key tips are active.

Common situations: Custom controls stealing focus inside their key-tip-activated command; third-party controls that move focus without registering as key tip scopes; refactors that remove the IsKeyTipScope attached-property setting.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/System.Windows.Controls.Ribbon/Microsoft/Windows/Controls/KeyTipService.cs:964

            IInputElement inputElement = exactMatchElement as IInputElement;
            if (inputElement != null)
            {
                inputElement.RaiseEvent(eventArgs);
                eventArgs.RoutedEvent = KeyTipAccessedEvent;
                inputElement.RaiseEvent(eventArgs);
            }

            // KeyTips might have been dismissed by one of the event handlers
            // hence check again.
            if (State != KeyTipState.None)
            {
                object newFocusedElement = Keyboard.FocusedElement;
                DependencyObject newScope = eventArgs.TargetKeyTipScope;
                if (newScope != null &&
                    !KeyTipService.GetIsKeyTipScope(newScope) &&
                    newScope != _currentGlobalScope)
                {
                    throw new InvalidOperationException(Microsoft.Windows.Controls.SR.ElementNotKeyTipScope);
                }
                if (newScope == null &&
                    KeyTipService.GetIsKeyTipScope(exactMatchElement))
                {
                    newScope = exactMatchElement;
                }

                if (newScope != null)
                {
                    // Show keytips for new scope in a dispatcher operation.
                    Dispatcher.CurrentDispatcher.BeginInvoke(
                        (Action)delegate()
                        {
                            ShowKeyTipsForScope(newScope, true);
                        },
                        DispatcherPriority.Loaded);
                }
                else

View on GitHub (pinned to 81131a70a4)