簡體   English   中英

將Windows窗體應用程序帶到前台的“正確”方法是什么?

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

我正在用C#編寫Windows窗體應用程序。 我需要能夠把它帶到前台。 經過一些谷歌搜索和實驗,我有一個看起來非常h​​acky的工作解決方案。

如果有的話,我想知道這樣做的優雅方式。 我需要應用程序恢復並前往前台,無論它是最小化,還是最小化,但在后台。

當前代碼如下所示:

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

你試過Form.Activate嗎?

此代碼似乎可以執行您想要的操作,如果最小化則將表單恢復為正常大小,然后激活它以設置焦點:

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

this.Activate();

警告:這很煩人! 如果它只是一個供您個人使用的應用程序,正如您所說,也許您可​​以忍受它。 :)

注意。 下面我復制了一個鏈接問題中 投票最多的答案 ,該問題與此問題相同。 答案是我發現解決這個問題的唯一純粹的C#答案。

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

它總是將所需的窗口帶到所有其他窗口的前面。

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);
    }
}

您可以將.TopMost設置為true,調用DoEvents() ,然后將.TopMost設置為false。 它仍然是hackish,但如果Activate和Show不起作用,它比最小化/重新顯示更好。

經過大量的反復試驗后,我得到了這段代碼。 這是經過測試的。 在將焦點傳遞給表單后,將在表單上調用BringToFront方法。 這使它彈出前面。

[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;
}

經過幾次嘗試,我發現了工作組合:

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

Form.TopMost設置為true將強制窗體窗口到前台。

set .TopMost = true

並使用

ShowDialog()

實際上,只需在Shown事件中調用Activate()

Example.Designer.cs

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

在您的Example.cs

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

即使您的表單由另一個進程啟動(例如:在不同線程中運行的啟動屏幕表單),這也有效。

我遇到了類似的問題

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

是一個非常令人滿意的解決方案

但是仍然不能保證表單會有焦點,因為TopMost可能並不總是有效,這取決於用戶之前與其他進程中的窗口進行交互的方式:

當在連續運行在不同線程中並由用戶代碼關閉的表單上使用時,TopMost不起作用

正如在另一個響應中已經說明的那樣,一個(當然是不優雅的)方法是使用user32.dll並調用本機方法,如果我們使用來自窗口調用者的一些未鏈接的進程或線程,這可能是有效的,在主調用者中設置為背景窗口(例如:總是在我們想要最頂層的窗口的頂部)。

這是部分復制,但只是為了方便:

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 );
    }
}

為了完整性,我添加了Windows SDK中可用常量的大多數引用

而不是使用windowstate最小化或topmost = false等等...

我有一個Winform應用程序......它啟動了一個自動化程序 - 我希望在執行自動化程序時最小化應用程序,然后在自動化程序完成后再次顯示。

這很簡單 - 只需使表單不可見,而另一個進程/線程/正在運行

 //hide the app

 this.Visible=false;

 //do something 

 some_form.ShowDialog();
 doSomethingHere();

 //reshow the app

 this.visible=true;  

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM