当IsFocusScope设置为True时,如何防止控件修改后丢失键盘焦点?
问题原因
这个现象是WPF焦点范围的默认行为导致的:
- 当你将容器的
FocusManager.IsFocusScope设置为True时,该容器会成为独立的逻辑焦点范围,内部的焦点默认是逻辑焦点,和全局键盘焦点是分离的。 - 当你在焦点范围内部触发控件操作(比如按空格键切换ToggleButton状态)时,WPF默认会将键盘焦点还原到该焦点范围外之前持有键盘焦点的元素,所以就会出现焦点自动移出区域的问题。
解决方案
根据你的使用场景可以选以下任意一种方案:
方案1:移除不必要的IsFocusScope设置
如果你给内部StackPanel设置IsFocusScope="True"不是为了实现工具栏、菜单这类需要保留原输入焦点的特殊需求,直接删除这个属性即可,修改后的XAML如下:
<StackPanel Width="100"> <ToggleButton Content="Test 1"/> <ToggleButton Content="Test 2"/> <ToggleButton Content="Test 3"/> <StackPanel> <ToggleButton Content="Test 4"/> <ToggleButton Content="Test 5"/> <ToggleButton Content="Test 6"/> </StackPanel> </StackPanel>
修改后内部的ToggleButton就会和前三个一样,按空格切换状态后焦点不会移位。
方案2:保留焦点范围,修改焦点还原行为
如果你必须保留IsFocusScope="True"的设置,可以给内部的StackPanel添加FocusManager.RestoreFocusMode="None"属性,禁止WPF自动还原该焦点范围外的键盘焦点,修改后的XAML如下:
<StackPanel Width="100"> <ToggleButton Content="Test 1"/> <ToggleButton Content="Test 2"/> <ToggleButton Content="Test 3"/> <StackPanel FocusManager.IsFocusScope="True" FocusManager.RestoreFocusMode="None"> <ToggleButton Content="Test 4"/> <ToggleButton Content="Test 5"/> <ToggleButton Content="Test 6"/> </StackPanel> </StackPanel>
这个方案不需要修改其他逻辑,也不会影响焦点范围的其他特性,适用于WPF 4.5及以上版本。
方案3:手动保持控件焦点
如果使用的是旧版本WPF,上面的方案不生效,可以给内部的ToggleButton添加Click事件处理,每次触发切换状态后手动将焦点留在当前控件上:
后台代码:
private void ToggleButton_Click(object sender, RoutedEventArgs e) { (sender as ToggleButton)?.Focus(); }
XAML绑定事件:
<StackPanel Width="100"> <ToggleButton Content="Test 1"/> <ToggleButton Content="Test 2"/> <ToggleButton Content="Test 3"/> <StackPanel FocusManager.IsFocusScope="True"> <ToggleButton Content="Test 4" Click="ToggleButton_Click"/> <ToggleButton Content="Test 5" Click="ToggleButton_Click"/> <ToggleButton Content="Test 6" Click="ToggleButton_Click"/> </StackPanel> </StackPanel>
内容的提问来源于stack exchange,提问作者Rachel
相关产品推荐
相关产品推荐

