dotnet / dotnet/wpf

Incorrect focus scope causing stack overflow with routed commands

Open
#10,696 1 comment 0 reactions 0 assignees View on GitHub
Investigate
Dominant language
C#
Stars
7.7k
Forks
1.3k
Avg merge
1d 11h
Merged PRs (30d)
61

Description

### Description

I'll use the minimal reproduction app below as an example here. When the button is clicked, a stack overflow happens because the focus scope is incorrectly determined for the button:
1. When clicked, the button gets the focus. `FocusManager` will find its focus scope to update `FocusedElement` property
2. `FocusManager` finds the focus scope by following the logical parent first, and then the visual parent. For the button, it will look at the `StackPanel`, `ContentControl`, `DockPanel`, and eventually deciding that the focus scope should be the `Window`. `FocusManager` the sets `FocusedElement` for the window.
3. At some point, `CommandManager.RaiseRequerySuggested` is dispatched, which raises `CanExecute` for the routed command on the menu item. Because the menu item itself doesn't have command bindings for `CanExecute`, it will find a parent in the tree that can handle it starting from the currently focused element
4. `CommandManager.OnCanExecute` is called on the button's visual parents. When it comes to the `Menu`, since the menu doesn't handle the routed command either, it will try to transfer the event to the focused element in its parent focus scope
5. The `Menu`'s parent focus scope is the `Window`, and the window's focused element is the button. So instead of going up the visual tree, the routed command bubbling actually goes back down. The search for a command binding enters a recursion

Generally speaking, this issue doesn't necessarily need to happen with a menu, but can be anything that is set to be a focus scope. A stack overflow will happen as long as the focus scope is inside a template (can also be a control template), the focused control is outside the template, and there's a control that hooks into can execute changed events for routed commands (a menu item, a button or a hyperlink)

### Reproduction Steps

Just create a WPF app with the following XAML in the main window. Open the menu and click on the button to trigger the overflow
```XML






















```

### Expected behavior

No stack overflow. The window's focused element should be null while the menu's focused element should be the button

### Actual behavior

It causes a stack overflow. The window's focused element is the button and the menu's focused element is null

### Regression?

_No response_

### Known Workarounds

_No response_

### Impact

_No response_

### Configuration

.NET 8

### Other information

_No response_

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.