Here's some sample code to reproduce the problem :
<StackPanel Width="100">
<ToggleButton Content="Test 1"/>
<ToggleButton Content="Test 2"/>
<ToggleButton Content="Test 3"/>
<StackPanel FocusManager.IsFocusScope="True">
<ToggleButton Content="Test 4"/>
<ToggleButton Content="Test 5"/>
<ToggleButton Content="Test 6"/>
</StackPanel>
</StackPanel>
If you tab through the ToggleButtons, the first 3 you can check/uncheck with the space bar without an issue because the keyboard focus remains on the item you change. But if you click/tab through boxes 4-6 that are in the focus scope and try to change them via the spacebar, the focus is reset outside of that focus scope, and subsequent spacebar presses get executed outside the focus scope.
How do I prevent the keyboard focus from leaving when changing data in a section where IsFocusScope=True
?
I found this behavior is "by design" for WPF. This post best explains it : https://stackoverflow.com/a/4954794/302677
The suggested solution of creating an attached property to implement your own focus scope handling is also in that link.
public static class FocusExtensions
{
private static bool SettingKeyboardFocus { get; set; }
public static bool GetIsEnhancedFocusScope(DependencyObject element) {
return (bool)element.GetValue(IsEnhancedFocusScopeProperty);
}
public static void SetIsEnhancedFocusScope(DependencyObject element, bool value) {
element.SetValue(IsEnhancedFocusScopeProperty, value);
}
public static readonly DependencyProperty IsEnhancedFocusScopeProperty =
DependencyProperty.RegisterAttached(
"IsEnhancedFocusScope",
typeof(bool),
typeof(FocusExtensions),
new UIPropertyMetadata(false, OnIsEnhancedFocusScopeChanged));
private static void OnIsEnhancedFocusScopeChanged(DependencyObject depObj, DependencyPropertyChangedEventArgs e) {
var item = depObj as UIElement;
if (item == null)
return;
if ((bool)e.NewValue) {
FocusManager.SetIsFocusScope(item, true);
item.GotKeyboardFocus += OnGotKeyboardFocus;
}
else {
FocusManager.SetIsFocusScope(item, false);
item.GotKeyboardFocus -= OnGotKeyboardFocus;
}
}
private static void OnGotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e) {
if (SettingKeyboardFocus) {
return;
}
var focusedElement = e.NewFocus as Visual;
for (var d = focusedElement; d != null; d = VisualTreeHelper.GetParent(d) as Visual) {
if (FocusManager.GetIsFocusScope(d)) {
SettingKeyboardFocus = true;
try {
d.SetValue(FocusManager.FocusedElementProperty, focusedElement);
}
finally {
SettingKeyboardFocus = false;
}
if (!(bool)d.GetValue(IsEnhancedFocusScopeProperty)) {
break;
}
}
}
}
}