[英]What is the “right” way to bring a Windows Forms Application to the foreground?
我正在用C#編寫Windows窗體應用程序。 我需要能夠把它帶到前台。 經過一些谷歌搜索和實驗,我有一個看起來非常hacky的工作解決方案。
如果有的話,我想知道這樣做的優雅方式。 我需要應用程序恢復並前往前台,無論它是最小化,還是最小化,但在后台。
當前代碼如下所示:
WindowState = FormWindowState.Minimized;
WindowState = FormWindowState.Normal;
BringToFront();
Focus();
你試過Form.Activate嗎?
此代碼似乎可以執行您想要的操作,如果最小化則將表單恢復為正常大小,然后激活它以設置焦點:
if (this.WindowState == FormWindowState.Minimized)
{
this.WindowState = FormWindowState.Normal;
}
this.Activate();
警告:這很煩人! 如果它只是一個供您個人使用的應用程序,正如您所說,也許您可以忍受它。 :)
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
可能並不總是有效,這取決於用戶之前與其他進程中的窗口進行交互的方式:
正如在另一個響應中已經說明的那樣,一個(當然是不優雅的)方法是使用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.