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
- Mark the target element as a key tip scope: KeyTipService.SetIsKeyTipScope(targetElement, true)
- Ensure focus changes during key tip mode target either a registered key tip scope or the current global scope
- Defer the focus change until after key tips are dismissed (e.g. in the Dispatcher at background priority after KeyTipService exits)
- 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
- Register custom focus targets with KeyTipService.SetIsKeyTipScope(element, true)
- Only redirect focus to registered key tip scopes while key tips are active
- Defer non-scope focus changes until key tip mode exits
- Audit custom controls for focus changes triggered by key tip activation
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
- Microsoft.Windows.Controls.SR.InvalidKeyTipOffset
- Microsoft.Windows.Controls.SR.UIA_OperationCannotBePerformed
- SetFocusFailed
- ArgumentOutOfRangeException(parameterName)
- ArgumentOutOfRangeException(parameterName)
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);
}
elseView on GitHub (pinned to 81131a70a4)