在WPF程序开发中,我们常常会发现默认的窗口标题栏过于不合适,而想修改其样式。有不少办法可以达到这一目的,但往往都不那么容易。而最简单的方法就是,直接不要默认的标题栏,转而在窗体内部重新制作一个,这样就可以充分使用我们所熟知的WPF的开发方式。不过,这样一来又有一个问题,即模拟的标题栏毕竟不是真正的标题栏,按住它无法拖动窗口,也无法双击最大化。Aland Li提供了一个好办法解决这一问题。
Windows使用WM_NCHITTEST窗口消息来判断鼠标的位置的类型,比如是否是标题栏,我们可以捕获这个消息,然后检查鼠标的坐标,如果在我们所设计的标题栏内,我们就告诉系统这个位置在标题栏上(返回HTCAPTION(2))。下面是详细代码:
private void Window_Loaded(object sender, RoutedEventArgs e) { // 添加一个消息过滤器 IntPtr hwnd = new WindowInteropHelper(this).Handle; HwndSource.FromHwnd(hwnd).AddHook(new HwndSourceHook(WndProc)); } private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam,
ref bool handled) { if(msg == WM_NCHITTEST) { // 获取屏幕坐标 Point p = new Point(); int pInt = lParam.ToInt32(); p.X = (pInt << 16) >> 16; p.Y = pInt >> 16; if(isOnTitleBar(PointFromScreen(p))) { // 欺骗系统鼠标在标题栏上 handled = true; return new IntPtr(2); } } return IntPtr.Zero; } private bool isOnTitleBar(Point p) { // 假设标题栏在0和100之间 if(p.Y >= 0 && p.Y < 100) return true; else return false; } private const int WM_NCHITTEST = 0x0084;
如此,只要点击窗口上方0-100的区域,便可以拖动窗口,也可以双击窗口进行最大化了。
而要去掉默认的标题栏,只需要将WindowStyle设为None即可。
BTW,其实并不一定要WPF才行吧,这个方法同时也适用于Winform,不过一般WPF程序更有美化标题栏的需求而已。