如果您希望应用程序中的窗口始终出现在不同应用程序的窗口之上,那么该BringWindowToTop
功能绝对不是您想要的。对于初学者,正如您所注意到的,您必须使用计时器重复调用该函数。这应该是您的第一个线索,即它是错误的 API。另一个问题是它只是将您的窗口带到其进程的 Z 顺序顶部,而不是系统上运行的所有其他进程。正如文档所解释的,
调用此函数类似于调用该SetWindowPos
函数以更改窗口在 Z 顺序中的位置。BringWindowToTop
不会使窗口成为顶级窗口。
最后一句话应该表明有更好的方法。Windows 内置了对顶层窗口的支持(即那些应该总是出现在其他窗口之上的窗口):这些被称为最顶层窗口。这正是你想要的。最顶层的窗口总是出现在非最顶层的窗口之上。
Raymond Chen 试图在他的博客上解释一些困惑。请注意,在这种情况下,HWND_TOP
等价于BringWindowToTop
。相反,你想要HWND_TOPMOST
.
使窗口处于最顶层的最简单方法是WS_EX_TOPMOST
在创建窗口时指定标志。.NET Framework 将大部分窗口创建工作隐藏在幕后,但您可以在需要时通过覆盖表单类的CreateParams
属性来自定义参数。
下面是一些使表单始终处于最顶层的示例代码:
Protected Overrides ReadOnly Property CreateParams() As CreateParams
Get
Const WS_EX_TOPMOST As Integer = &H00000008
Dim cp As CreateParams = MyBase.CreateParams
cp.ExStyle = cp.ExStyle Or WS_EX_TOPMOST
Return cp
End Get
End Property
如果您想在运行时切换窗口的最顶层状态,这将不起作用。为此,您将不得不 P/InvokeSetWindowPos
函数。P/Invoke 与您过去在 VB6 中使用Declare
语句所做的类似,但在 .NET 世界中语义略有变化——这就是为什么您不能Declare
在 VB.NET 中使用旧的 VB6 语句的原因。
下面是 VB.NET 的代码:
<DllImport("user32.dll", SetLastError:=True)> _
Private Shared Function SetWindowPos(ByVal hWnd As IntPtr, ByVal hWndInsertAfter As IntPtr, ByVal X As Integer, ByVal Y As Integer, ByVal cx As Integer, ByVal cy As Integer, ByVal uFlags As Integer) As Boolean
End Function
Private Const SWP_NOSIZE As Integer = &H1
Private Const SWP_NOMOVE As Integer = &H2
Private Shared ReadOnly HWND_TOPMOST As New IntPtr(-1)
Private Shared ReadOnly HWND_NOTOPMOST As New IntPtr(-2)
Public Function MakeTopMost()
SetWindowPos(Me.Handle(), HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE Or SWP_NOSIZE)
End Function
Public Function MakeNormal()
SetWindowPos(Me.Handle(), HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE Or SWP_NOSIZE)
End Function