【问题标题】:C# New form never gains focusC# 新表单永远不会获得焦点
【发布时间】:2009-05-12 17:40:41
【问题描述】:

我一直在尝试编写一个带有自己的选项窗口的小应用程序。当我尝试启动窗口时,我似乎永远无法将注意力集中在新表单上。这不是 mdi 表单,而只是我在用户从菜单中选择选项时创建的新表单。需要注意的是,Form.Show 是 return false,这意味着新的表单永远不会获得焦点。

我尝试了多种加载表单的方法,但都失败了:

来自调用表单:

ServerForm SF = new ServerForm(ref DataLoader, false);
SF.Show();
SF.Focus();
// Fails

在表单内部:

this.Show();
this.BringToFront();
this.Activate();
this.TopMost = true;
// Fails

将表单设置为可选:

this.SetStyle(System.Windows.Forms.ControlStyles.Selectable, true);
...
ServerForm SF = new ServerForm(ref DataLoader, false);
SF.Show();
SF.Focus();
// Fails

使用旧 API:

[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern int ShowWindow(IntPtr handle, int nCmdShow);    
ServerForm SF = new ServerForm(ref DataLoader, false);
ShowWindow(SF.Handle, 3);
SF.Show();
SF.Focus();
// Fails

传入父级

ServerForm SF = new ServerForm(ref DataLoader, false);
SF.Show(this);
SF.Focus();
// Fails

在所有这些情况下,表单都会显示,但生成的表单仍将焦点放在新表单上。即使我在创建新表单之前禁用旧表单也会发生这种情况。

有什么建议吗?

【问题讨论】:

    标签: c# forms focus


    【解决方案1】:

    这是因为Form.canFocus() 在表单加载时为假。在Form.Shown 事件上使用Form.Activate()。就是这样。

    private void ServerForm_Shown(object sender, EventArgs e)
    {
        this.Activate();
    }
    

    【讨论】:

      【解决方案2】:

      TopMost 表单属性设置为true。那么

      在program.cs中:

      var formLogin = new frmLogin();
      formLogin.ShowDialog();
      
      
      if (formLogin.DialogResult == DialogResult.Yes)
      {
              Application.Run(new frmMain());
      }
      

      在表单中登录:

      [DllImport("user32")]
      public static extern int SetForegroundWindow(IntPtr hwnd);         
      
      ...
      
      private void frmLogin_Shown(object sender, EventArgs e)
      {
        SetForegroundWindow(this.Handle);
      }
      
      private void frmLogin_Deactivate(object sender, EventArgs e)
      {
          TopMost = false;
      
      }
      

      【讨论】:

        【解决方案3】:

        我解决了这个问题(感谢@Joel Coehoorn):

        form.WindowState = FormWindowState.Minimized;
        form.Shown += delegate(Object sender, EventArgs e) {
            ((Form)sender).WindowState = FormWindowState.Normal;
        };
        form.ShowDialog();
        

        【讨论】:

          【解决方案4】:

          请记住,winforms 应用程序中只允许一个用户界面线程。

          您在调用Form.Show() 之后 是否在父表单上进行任何操作?这 可能会导致父窗体再次聚焦。

          删除您用来尝试集中注意力的所有内容,激活表单并仅依赖于对Form.Show() 的调用。这应该足以加载表单并专注于它。如果有的话,在您的菜单项处理程序中。致电Show() 后将所有内容注释掉,看看是否可行。向后工作以查看导致您的父表单重新聚焦的原因。

          【讨论】:

          • 调用中这个Form.Show之后什么都没有。问题是 Form.Show 本身没有返回 true。它不像表格是暂时获得焦点。它从一开始就没有得到关注。
          • 关于你的第一句话:你如何告诉系统哪个是你的应用程序中的用户界面线程?
          • 你不能手动指定这个。如果您不创建自己的线程,则不必担心。如果您确实创建了自己的线程,则可以使用 InvokeRequired 属性判断您正在哪个线程上执行。
          【解决方案5】:

          这似乎有效。首先我创建新表单:

          private void changeDefaultServerToolStripMenuItem_Click(object sender, EventArgs e)
          {
              this.Enabled = false;
              ServerForm SF = new ServerForm(ref DataLoader, true);
          }
          

          然后在新表单的构造函数中执行以下操作:

          this.BringToFront();
          this.CenterToParent();
          this.TopMost = true;
          this.ShowDialog();
          

          显然 Form.Show 和 Form.ShowDialog 之间存在某种幕后差异。不太确定它是什么,我只能认为它与以某种方式设置活动父母有关。在调用构造函数之后添加代码似乎不会将焦点重新归还给父表单。这是不应该的。

          【讨论】:

          • 你为什么要让它成为TopMost?除非有真正令人信服的理由,否则您不应该这样做。此外,构造的表单通常不应该像那样在自身上调用 Show。
          • Show 和 ShowDialog 的区别在于 ShowDialog 显示的是模态对话框。除非没有要指定的父级,否则应始终使用 ShowDialog() 指定父级。
          • 我添加了 TopMost,因为我想确保它显示在顶部。它总是需要吗?不会。但是,它确保它在可能不会发生时发生。
          • 它还确保当用户希望窗口在后台时它保持在顶部。除非必须,否则不要使用 TopMost。作为用户,我知道我对滥用 TopMost 的软件感到非常恼火。足够我不会从制造它的公司购买软件,如果有选择的话。
          【解决方案6】:

          尝试致电ShowDialog(this)。当我遇到同样的问题时,它对我有帮助。

          【讨论】:

            【解决方案7】:

            您是否尝试在Form.Show() 中设置正确的父窗口?

            例如:

            using(ServerForm SF = new ServerForm(ref DataLoader, false)) // if ServerForm is IDisposable
            {
                SF.Show(this);
            }
            

            编辑:

            有些事情不在您的问题范围内。您拥有的窗口是 TopMost 窗口吗?

            【讨论】:

            • 没有。可悲的是,这不起作用,但我将它添加到列表中。此外,您不能使用 using 关键字生成表单,因为一旦超出范围就会终止表单。
            • 啊,是的,我通常与 ShowDialog(parent) 一起使用,而不是 Show(parent)。
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2021-04-15
            • 1970-01-01
            • 1970-01-01
            • 2021-03-08
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多