如何去掉WinForm或者WPF的最大化和最小化按钮
有时候我们希望对我们的WinForm或者WPF控件做一些定制,比如去掉最大化和最小化按钮,怎么做呢?
WinForm
WinForm去掉最大化和最小化按钮:1
2MaximizeBox = false;
MinimizeBox = false;
WinForm的最大化和最小化按钮和能否改变窗口大小是两个属性,所以上面的代码只是把最小化和最大化按钮去掉了,但是窗口还能改变大小。
下面的代码是不允许改变WinForm的窗口大小,但是最大化和最小化按钮还是能点的。1
FormBorderStyle = FormBorderStyle.FixedSingle;
WPF
WPF没有API可以直接去掉最大化和最小化按钮的,但是我们可以通过ResizeMode
来曲线救国,如果设置窗口不能改变大小,那么最大化和最小化按钮也就没有了,如下所示:1
ResizeMode = System.Windows.ResizeMode.NoResize;
另外还有一个办法是通过设置WindowStyle
来实现,但是这个会把关闭的按钮也弄没,如下所示:1
WindowStyle = WindowStyle.None;
这两种方式都不是很好,会有一些副作用,那还有别的办法吗?
用Windows的API:SetWindowLongPtr
SetWindowLongPtr是Windows的一个API,作用是改变窗口的属性。函数签名如下:1
2
3
4
5LONG_PTR WINAPI SetWindowLongPtr(
_In_ HWND hWnd,
_In_ int nIndex,
_In_ LONG_PTR dwNewLong
);
第一个参数是窗口句柄。第二个参数是offset,当它的值是GWL_STYLE
(-16)时,可以设置窗口风格。第三个参数是要设置的值,比如针对GWL_STYLE
的可能取值参见Window Styles。里面就有最大化(WS_MAXIMIZEBOX=0x00010000L
)和最小化按钮(WS_MINIMIZEBOX=0x00020000L
)。所以我们可以通过设置这两个值去掉最大化和最小化按钮。
在调用SetWindowLongPtr之前要调用GetWindowLongPtr来获取当前Window的信息,确保我们只是把最大化和最小化按钮去了。
在调用SetWindowLongPtr之前要调用SetWindowPos以确保我们的设置生效了。
SetWindowLongPtr和GetWindowLongPtr都是针对64位程序的。
尽管MSDN上写的是这两个对32位也有效,但是其实如果直接DllImport
这两个API使用时会报EntryPointNotFoundException
。所以我们要根据当前应用程序是32位还是64位使用不同的DllImport
API。32位下需要用GetWindowLong和SetWindowLong。
下面的代码对WinForm和WPF都有效:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38private const int GWL_STYLE = -16;
private const int WS_MAXIMIZEBOX = 0x10000;
private const int WS_MINIMIZEBOX = 0x20000;
private const int SWP_NOMOVE = 0x0002;
private const int SWP_NOSIZE = 0x0001;
private const int SWP_NOZORDER = 0x0004;
private const int SWP_FRAMECHANGED = 0x0020;
[ ]
private static extern int GetWindowLong32(IntPtr hWnd, int nIndex);
[ ]
extern private static int GetWindowLongPtr(IntPtr hwnd, int index);
[ ]
extern private static int SetWindowLong32(IntPtr hwnd, int index, int value);
[ ]
extern private static int SetWindowLongPtr(IntPtr hwnd, int index, int value);
[ ]
public static extern bool SetWindowPos(IntPtr hWnd, int hWndInsertAfter, int x, int Y, int cx, int cy, int wFlags);
private static void HideMinMaxButtons(IntPtr hwnd)
{
if (IntPtr.Size == 4)
{
var currentStyle = GetWindowLong32(hwnd, GWL_STYLE);
SetWindowLong32(hwnd, GWL_STYLE, (currentStyle & ~WS_MAXIMIZEBOX & ~WS_MINIMIZEBOX));
}
else
{
var currentStyle = GetWindowLongPtr(hwnd, GWL_STYLE);
SetWindowLongPtr(hwnd, GWL_STYLE, (currentStyle & ~WS_MAXIMIZEBOX & ~WS_MINIMIZEBOX));
}
//call SetWindowPos to make sure the SetWindowLongPtr take effect according to MSDN
SetWindowPos(hwnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
}
另外要注意的一点事,在调用过HideMinMaxButtons
之后不能在调用其他会改变窗口风格的C#的API。比如如果WinForm,在这个函数之后在调用一下FormBorderStyle = FormBorderStyle.Sizable;
,或者WPF调用一下ResizeMode = System.Windows.ResizeMode.CanResize;
,那么最大化和最小化按钮就又回来了。