如何将我的应用程序窗口置于前台?

111

如何将我的应用程序窗口置于前台?例如,当我的应用程序需要关注时。

这是为我个人的程序。我需要那个功能。

这就是我得到的东西。但它并不总是有效

public void BringToFrontToEnterCaptha()
{
    if (InvokeRequired)
    {
        Invoke(new Action(BringToFrontToEnterCaptha));
    }
    else
    {
        this.TopMost = true;
        this.Focus();
        this.BringToFront();
        this.textBox1.Focus();
        this.textBox1.Text = string.Empty;
        System.Media.SystemSounds.Beep.Play();
    }
}

public void BringToBackAfterEnterCaptha()
{
    if (InvokeRequired)
    {
        Invoke(new Action(BringToBackAfterEnterCaptha));
    }
    else
    {
        this.TopMost = false;
    }
}

我从后台工作线程调用它们。

BringToFrontToEnterCaptha();
while (!ready)
{
    Thread.Sleep(100);
}
BringToBackAfterEnterCaptha();
Thread.Sleep(300);

在按下“接受”按钮后,布尔变量“ready”将被设置为true。

它的效果很好,但并非总是如此。


当您的应用程序需要关注时,它是否具有输入焦点? - David Heffernan
输入焦点怎么办?如果没有它,你就不能轻易地将应用程序置于前台。 - David Heffernan
我会将此添加为评论,如建议的那样:我非常担心有一天你的“个人”程序逃脱出来并强制性地施加给某些毫不知情的用户。如果你需要这个,也许你的设计需要重新审查... - Vincent Vancalbergh
1
@VincentVancalbergh 那是一个“私有”的程序。但如果它不弹出给用户,那么这个程序就没有意义了。这就是整个想法。而且它运行得非常好。现在它已经不再使用了。 - Hooch
有趣的是,我正在寻找一种通用解决方案来将窗口置于前台,并找到了这个答案,它似乎出于与我相同的原因 - 偶尔需要通过验证码 :) - Alex P.
7个回答

214

以下是一段对我有效的代码

this.WindowState = FormWindowState.Minimized;
this.Show();
this.WindowState = FormWindowState.Normal;

它总是将期望的窗口置于所有其他窗口前面。


14
在我使用谷歌搜索并尝试了各种方法后,大家一直坚持说激活和专注是关键。然而,这个方法是唯一对我有效的。感谢你,因为我从未想到这个诀窍。 - Reactgular
2
谢谢。在我找到的所有解决方案中,这是唯一一个似乎每次都有效的。+1 - Alex
2
太棒了!这是唯一对我有效的方法。适用于WinForm。幸运的是,我可以最小化和恢复我的应用程序,因为它没有任何可见的UI。这在另一种情况下也很有用:https://dev59.com/C3VC5IYBdhLWcg3wjx1d#4831839 - gsb
1
谢谢 - 在Form::Load事件中调用我的启动屏幕的Hide()方法使我的GUI处于后台,只有这个方法(或根据as-cii的答案调用Form.Activate()方法)似乎能够将其带回! - Jon Cage
4
使用 Activate() 方法更好。在您的情况下,最好检查并记住窗口是否处于“最大化”状态。否则,当窗口最大化时,将其还原为“正常”状态。 - i486
显示剩余10条评论

98

使用 Form.Activate()Form.Focus() 方法。


我在Form1_Load函数中使用Focus(),但它不起作用(使用Windows 8.1)。 - Simon
22
Form.Activate() 可以独立使用 - 谢谢! - Jon Cage
2
“Activate”会使Windows将当前窗体置于操作系统中打开的任何其他应用程序之前。另一方面,“bring to front”只会使所需的窗体显示在当前应用程序中其他窗体的前面(而不是整个操作系统)。 - Simon Dugré
Form.Focus() 在我的情况下没有起作用。.Activate() 完美地解决了问题。在这个线程中更高级的解决方案是使用 .Minimized 和 .Normal,但是会有一个不理想的最小化/还原动画,所以对我来说 .Activate() 才是正确的解决方案。 - blitz_jones
这应该是被接受的答案。Form.Activate() 是一个可行的方法。 - Mike Keskinov

64

虽然我同意大家的看法,这种行为并不好,但这是代码:

[DllImport("User32.dll")]
public static extern Int32 SetForegroundWindow(int hWnd);   


SetForegroundWindow(Handle.ToInt32());

更新

David 是完全正确的,为了完整起见,我包括了必须满足的条件列表(+1 给 David!):

  • 该进程是前台进程。
  • 该进程是由前台进程启动的。
  • 该进程接收到了最后一个输入事件。
  • 没有前台进程。
  • 前台进程正在被调试。
  • 前台没有被锁定(参见 LockSetForegroundWindow)。
  • 前台锁定超时已过期(参见 SystemParametersInfo 中的 SPI_GETFOREGROUNDLOCKTIMEOUT)。
  • 没有菜单处于活动状态。

4
请阅读此条件列表,以确保其适用于此操作。 - David Heffernan
13
Form.Activate() 调用 SetForegroundWindow(),避免了使用 PInvoke 的需要。 - Tony Edgecombe
它与我的启动画面完美配合,谢谢 :) - Jerzy Gebler
这是唯一对我有效的解决方案。我不知道原因的错误是Visual Studio在运行项目后没有自动切换焦点到应用程序。通常情况下,对于我所有的其他应用程序,切换都是自动完成的,但对于其中一个应用程序,我必须在仅针对调试模式的程序开始时使用此hack。 - Samuel
尝试了这里提供的所有解决方案,这是唯一一个有效的解决方案,但Dennis(来自Microsoft)的要点并没有完全对齐。我已经在使用SetForeGroundWindow()将不同的应用程序置于前台,然后想要弹出一个对话框以输入与该应用程序相关的一些信息。在看到这个要点之前,我尝试了这里提供的所有.Net解决方案(以及自己死胡同的一半),然后想到“当然”。即使我违反了“没有前景进程”的要点,但我正在使用管理员权限运行,这很可能是它能够工作的原因。 - shooky
这是唯一一个对我有效的解决方案。我在另一个线程上有一个等待对话框,当我关闭它时,我想将焦点转移到主对话框,这是唯一能做到这一点的答案。 - user890332

45

6
如果应用程序没有输入焦点,这个能起作用吗? - David Heffernan
21
这对我不起作用。 - Jon Cage
1
@JonCage 尝试使用 Application.OpenForms["yourForm"].BringToFront(); - FireFalcon
29
这是不正确的。Control.BringToFront会将控件带到托管控件的前面,例如,您可能会将TextBox带到Label的前面,以确保标签的空格不会遮挡TextBox的一部分。Form从Control继承了这个方法,在MDI子窗体中可以用来更改Form的z顺序 - 即Form被托管在另一个Form中。它不会将一个窗体置于另一个应用程序的前面。 - jo0ls
10
Form.Activate() 有效,给下面的回答点赞。 - Sire
目前来看,这对我有效。 - Kai Wang

33

这个有效:

if (WindowState == FormWindowState.Minimized)
    WindowState = FormWindowState.Normal;
else
{
    TopMost = true;
    Focus();
    BringToFront();
    TopMost = false;
}

在这里的所有建议中,这是唯一一个对我有用的。 :) - MojoDK
Forms.Activate() 能够结束这个解决方案吗?非常奇怪!你确定吗? - lupok
非常确定。我已经尝试将我的应用程序简化为可以在此处发布的内容,但首先它并未复制出问题。我一定是在某个地方做了一些奇怪的设置或操作,导致您的建议失败 :-/ - Jon Cage
不需要使用“TopMost”“hack”,只需两行代码:Activate(); BringToFront();。不确定哪个应该先执行。 - i486

23

在看到这篇文章之前,我已经想出了一个解决方案——切换TopMost属性:

this.TopMost = true;
this.TopMost = false;

我在我的表单构造函数中有这段代码,例如:

public MyForm()
{
    //...

    // Brint-to-front hack
    this.TopMost = true;
    this.TopMost = false;

    //...
}

1
在罕见情况下,这可能会导致蓝屏死机,例如使用更改其他窗口的最上层的程序,比如虚拟/多个桌面应用程序。 - Raphael Smit
不能。一个用户模式故障不会导致蓝屏死机。 - lerthe61
这应该是答案。 - Bobby Turkalino
切换 this.TopMost 会增加一点延迟。除非您反复调用此操作,例如在 Resize 事件处理程序中(不要问我为什么这样做),否则它是无法察觉的。 - Walter Stabosz
这个可以工作。总会有与“正常”或“预期”行为不同的偏差,因此您可能会遇到这种情况,当我使用它已经有一段时间了,很少需要调整它。VS2022 / .NET6 - Pepik
显示剩余2条评论

9

我使用 SwitchToThisWindow 将应用程序置于前台,如下例所示:

static class Program
{
    [DllImport("User32.dll", SetLastError = true)]
    static extern void SwitchToThisWindow(IntPtr hWnd, bool fAltTab);



    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main()
    {
        bool createdNew;
        int iP;
        Process currentProcess = Process.GetCurrentProcess();
        Mutex m = new Mutex(true, "XYZ", out createdNew);
        if (!createdNew)
        {
            // app is already running...
            Process[] proc = Process.GetProcessesByName("XYZ");

            // switch to other process
            for (iP = 0; iP < proc.Length; iP++)
            {
                if (proc[iP].Id != currentProcess.Id)
                    SwitchToThisWindow(proc[0].MainWindowHandle, true);
            }

            return;
        }

        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new form());
        GC.KeepAlive(m);

    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接