WPF C# 鼠标左键按下触发焦点丢失时获取源控件并重聚焦问题
WPF TextBox 失焦校验拦截焦点解决方案
核心问题原因
你在LostFocus事件中设置焦点不生效,是因为LostFocus是冒泡事件,触发时新控件的焦点获取逻辑已经进入事件队列,你直接调用Focus()的操作会被后续的焦点转移逻辑覆盖,自然也无法阻止焦点跳转。
最优解决方案:使用PreviewLostKeyboardFocus隧道事件
这个事件在焦点真正完成转移前触发,你可以直接中断焦点路由,完全避免焦点跳走的问题,同时事件的sender参数就是你需要的失焦源控件,无需额外捕获。
单控件绑定示例
XAML代码:
<TextBox x:Name="InputTextBox" PreviewLostKeyboardFocus="InputTextBox_PreviewLostKeyboardFocus" />
后台事件代码:
private void InputTextBox_PreviewLostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e) { var sourceTextBox = sender as TextBox; if (sourceTextBox == null) return; // 替换为你的自定义校验逻辑 bool isInputValid = !string.IsNullOrWhiteSpace(sourceTextBox.Text) && int.TryParse(sourceTextBox.Text, out _); if (!isInputValid) { // 中断事件路由,阻止焦点转移 e.Handled = true; // 可选配置:标红控件、全选文本方便用户直接修改 sourceTextBox.BorderBrush = Brushes.Red; sourceTextBox.SelectAll(); } else { sourceTextBox.ClearValue(TextBox.BorderBrushProperty); } }
全局拦截所有TextBox失焦操作
如果需要对窗口内所有TextBox统一做校验拦截,无需逐个绑定事件,在窗口构造函数中添加全局事件注册即可:
public MainWindow() { InitializeComponent(); // 注册全局TextBox失焦前事件处理 EventManager.RegisterClassHandler(typeof(TextBox), TextBox.PreviewLostKeyboardFocusEvent, new KeyboardFocusChangedEventHandler(GlobalTextBoxPreviewLostFocus), true); } private void GlobalTextBoxPreviewLostFocus(object sender, KeyboardFocusChangedEventArgs e) { // 同上写入校验逻辑即可,sender为当前失焦的TextBox控件 }
兼容方案:LostFocus事件异步设置焦点
如果你必须沿用LostFocus事件的现有逻辑,可以通过Dispatcher把焦点设置操作排到当前焦点处理逻辑之后执行,也能实现焦点回切,缺点是会有轻微的焦点闪烁:
private void InputTextBox_LostFocus(object sender, RoutedEventArgs e) { var sourceTextBox = sender as TextBox; if (sourceTextBox == null) return; bool isInputValid = !string.IsNullOrWhiteSpace(sourceTextBox.Text) && int.TryParse(sourceTextBox.Text, out _); if (!isInputValid) { // 异步设置焦点,优先级设为Input确保在当前焦点转移完成后执行 Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Input, new Action(() => { sourceTextBox.Focus(); sourceTextBox.SelectAll(); })); } }
内容的提问来源于stack exchange,提问作者Perini Luca
相关产品推荐
相关产品推荐

