简体   繁体   中英

What is the “right” way to bring a Windows Forms Application to the foreground?

I am writing a Windows Forms Application in C#. I need to be able to bring it to the foreground. After some Googling and experimentation, I have a working solution that looks pretty hacky.

I would like to know the elegant way to do this, if there is one. I need the app to restore and come to the foreground whether it was minimized, or not minimized but in background.

Current code looks like this:

WindowState = FormWindowState.Minimized;
WindowState = FormWindowState.Normal;
BringToFront();
Focus();

Have you tried Form.Activate ?

This code seems to do what you want, by restoring the form to normal size if minimized and then activating it to set the focus:

if (this.WindowState == FormWindowState.Minimized)
{
    this.WindowState = FormWindowState.Normal;
}

this.Activate();

Warning: this is annoying! If it's just an app for your personal use, as you say, maybe you can live with it. :)

Note. Below I have copied the most voted answer in a linked question closed as a duplicate to this one. That answer is the only pure C# answer I've found that solves this problem.

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

It always brings the desired window to the front of all the others.

private static class User32
{
    [DllImport("User32.dll")]
    internal static extern IntPtr SetForegroundWindow(IntPtr hWnd);

    [DllImport("user32.dll")]
    internal static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);

    internal static readonly IntPtr InvalidHandleValue = IntPtr.Zero;
    internal const int SW_MAXIMIZE = 3;
}
public void Activate()
{
    Process currentProcess = Process.GetCurrentProcess();
    IntPtr hWnd = currentProcess.MainWindowHandle;
    if (hWnd != User32.InvalidHandleValue)
    {
        User32.SetForegroundWindow(hWnd);
        User32.ShowWindow(hWnd, User32.SW_MAXIMIZE);
    }
}

You can set .TopMost to true, call DoEvents() , and then set .TopMost back to false. It's still hackish, but if Activate and Show aren't working it's better than minimizing/re-showing.

After a lot of trial and error I got to this code. This is tested. The BringToFront method is called on your form after the focus has been passed on to it. This makes it pop up in front.

[DllImport("user32.dll")]
static extern bool SetForegroundWindow(IntPtr hWnd);

public static bool BringToFrontCustom(Form f)
{
    bool toReturn = true;
    try
    {
        //This is the same as the name of the executable without the .exe at the end            
        Process[] processes = Process.GetProcessesByName("MyFormName");

        SetForegroundWindow(processes[0].MainWindowHandle);
        f.BringToFront();
    }
    catch(Exception e)
    {
         toReturn = false;
         MessageBox.Show("Something went wrong, Please bring the window to front manually");
    }
    return toReturn;
}

After several attempts I found out working combination:

form.Show();
form.WindowState = FormWindowState.Normal;
form.Activate();

Form.TopMost设置为true将强制窗体窗口到前台。

set .TopMost = true

and use

ShowDialog()

Actually, just call Activate() inside Shown event.

In your Example.Designer.cs :

this.Shown += new System.EventHandler(this.Example_Shown);

In your Example.cs :

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

This worked even if your form is being launch by another process (ex: a splash screen form running in a different thread).

I had a similar problem, to which

form.TopMost = true;
form.Activate();

was quite a satisfying solution.

But it's still not guaranteed that the form will have focus then, because TopMost might not always work, depending on how the user has interacted before with the windows in other processes:

TopMost does not work when used on Forms running in consecutively in different threads and closed by user code

As already stated in another response, one (of course unelegant) way to do this would be by using user32.dll and call the native methods, this can be valid if we are using some unlinked process or thread from the window caller, that was set in the main caller as a background window (eg: always on top for the window that we want topmost).

this was partially copied, but only for easyness:

public enum WindowPos : int
{
    HWND_NOTOPMOST=-2,
    HWND_TOPMOST=-1,
    HWND_TOP=0,
    HWND_BOTTOM=1
}
public enum WindowFlags : uint
{
    SWP_NOSIZE=0x0001,
    SWP_NOMOVE=0x0002,
    SWP_NOZORDER=0x0004,
    SWP_NOREDRAW=0x0008,
    SWP_NOACTIVATE=0x0010,
    SWP_FRAMECHANGED=0x0020,  /* The frame changed: send WM_NCCALCSIZE */
    SWP_SHOWWINDOW=0x0040,
    SWP_HIDEWINDOW=0x0080,
    SWP_NOCOPYBITS=0x0100,
    SWP_NOOWNERZORDER=0x0200,  /* Don't do owner Z ordering */
    SWP_NOSENDCHANGING=0x0400  /* Don't send WM_WINDOWPOSCHANGING */
}
public enum ShowWindowCommands : int
{
    SW_HIDE=0,
    SW_SHOWNORMAL=1,
    SW_NORMAL=1,
    SW_SHOWMINIMIZED=2,
    SW_SHOWMAXIMIZED=3,
    SW_MAXIMIZE=3,
    SW_SHOWNOACTIVATE=4,
    SW_SHOW=5,
    SW_MINIMIZE=6,
    SW_SHOWMINNOACTIVE=7,
    SW_SHOWNA=8,
    SW_RESTORE=9,
    SW_SHOWDEFAULT=10,
    SW_FORCEMINIMIZE=11,
    SW_MAX=11
}

private static class User32
{
    [DllImport("user32.dll")]
    internal static unsafe extern IntPtr SetForegroundWindow(IntPtr hWnd);

    [DllImport("user32.dll")]
    internal static unsafe extern bool ShowWindow(IntPtr hWnd, int nCmdShow);

    [DllImport("user32.dll")]
    internal static unsafe extern bool SetWindowPos(IntPtr hWnd, int hWndPutAfter, int x, int y, int cx, int cy, uint flags);

    [DllImport("user32.dll")]
    internal static unsafe extern IntPtr SetFocus( IntPtr hWnd );
}
public void Activate()
{
    Process currentProcess = Process.GetCurrentProcess();
    IntPtr hWnd = currentProcess.MainWindowHandle;
    if (hWnd != IntPtr.Zero)
    {
        User32.SetWindowPos(hWnd, (int)WindowPos.Top, 0, 0, 0, 0, (uint)(WindowFlags.SWP_NOMOVE | WindowFlags.SWP_NOSIZE));
        User32.ShowWindow(hWnd, (int)ShowWindowCommands.SW_SHOW);
        User32.SetForegroundWindow(hWnd);
        User32.SetFocus( hWnd );
    }
}

For completeness I added most references from the constants that are available in the windows SDK

Instead of using windowstate minimize or topmost=false etc etc...

I have a Winform App... it launches an automation routine - I wanted the app minimized when the automation sequence is performed then presented again after the automation sequence was complete.

It was easy - just make the form not visible while the other process/thread/ whatever is running

 //hide the app

 this.Visible=false;

 //do something 

 some_form.ShowDialog();
 doSomethingHere();

 //reshow the app

 this.visible=true;  

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM