WinForm中Invoke调用ShowDialog后Form控件无法获焦问题求助
问题
场景如下:
- 有一个线程在FormA上运行
- 该线程触发一个事件
- 在事件处理中通过
FormA.InvokeIfRequired显示模态窗体FormB(LoginForm) - 在FormB的
Shown事件里调用TxtUsername.Focus()让文本框获焦 - 问题:调用
FormA.InvokeIfRequired(() => { FormB.ShowDialog(); })时,FormB上的文本框无法获焦,只能手动点击才能获取焦点
相关代码:
FormA的事件处理方法
private void OnMessage() { this.InvokeIfRequired(() => { var loginForm = new LoginForm(); loginForm.ShowDialog(); }); }
FormB的Shown事件处理
private void LoginForm_Shown(object sender, EventArgs e) { TxtUsername.Focus(); }
InvokeIfRequired扩展方法
public static void InvokeIfRequired(this Control control, MethodInvoker action) { if (control.InvokeRequired) { control.Invoke(action); } else { action(); } }
解决方案
方法1:用Select()替代Focus()
WinForms中Focus()有时无法正确抢占焦点,Select()会同时设置控件的焦点和选择状态,可靠性更高:
private void LoginForm_Shown(object sender, EventArgs e) { TxtUsername.Select(); }
方法2:延迟执行焦点设置
窗体Shown事件触发时,焦点机制可能未完全初始化,用BeginInvoke将焦点操作延迟到消息队列末尾执行:
private void LoginForm_Shown(object sender, EventArgs e) { BeginInvoke((MethodInvoker)delegate { TxtUsername.Select(); }); }
方法3:利用控件TabIndex属性
将TxtUsername的TabIndex设为0,窗体加载后默认焦点会自动落在该控件上,无需手动调用焦点方法。
方法4:确保窗体激活
在FormB的Shown事件中先激活窗体,再设置控件焦点:
private void LoginForm_Shown(object sender, EventArgs e) { this.Activate(); TxtUsername.Select(); }
内容的提问来源于stack exchange,提问作者canowar
相关产品推荐
相关产品推荐

