对于WinForms应用程序,表单和控件尽可能接近本机Win32 API;一个简单的方法是重写表单中的
WndProc()
处理程序,处理WM_NCHITTEST
窗口消息,并通过返回HTCAPTION
来欺骗系统,使其认为在框架区域上的点击实际上是在标题栏上的点击。我已经在自己的WinForms应用程序中这样做,效果非常好。在WPF中,我也可以实现类似的
WndProc()
方法,并将其钩到我的WPF窗口句柄上,同时将窗口框架扩展到客户端区域,像这样:// In MainWindow
// For use with window frame extensions
private IntPtr hwnd;
private HwndSource hsource;
private void Window_SourceInitialized(object sender, EventArgs e)
{
try
{
if ((hwnd = new WindowInteropHelper(this).Handle) == IntPtr.Zero)
{
throw new InvalidOperationException("Could not get window handle for the main window.");
}
hsource = HwndSource.FromHwnd(hwnd);
hsource.AddHook(WndProc);
AdjustWindowFrame();
}
catch (InvalidOperationException)
{
FallbackPaint();
}
}
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
switch (msg)
{
case DwmApiInterop.WM_NCHITTEST:
handled = true;
return new IntPtr(DwmApiInterop.HTCAPTION);
default:
return IntPtr.Zero;
}
}
问题在于,由于我盲目地设置了
handled = true
并返回HTCAPTION
,因此点击窗口图标或控制按钮以外的任何地方都会导致窗口被拖动。也就是说,下面红色部分中的所有内容都会导致拖动。这甚至包括窗口边缘的调整手柄(非客户区域)。我的WPF控件,即文本框和选项卡控件,也因此停止接收点击:
我想要的是仅有:
- 标题栏和
- 客户端区域中未被我的控件占用的区域...
- ...可以拖动。
也就是说,我只想让这些红色区域可以拖动(客户端区域+标题栏):
WndProc()
方法以及窗口的其余XAML/代码后台,以确定哪些区域应返回HTCAPTION
,哪些不应该? 我考虑使用Point
来检查单击的位置与控件位置的关系,但我不确定如何在WPF中实现。 编辑[4/24]:其中一种简单的方法是让一个不可见的控件,甚至是窗口本身,通过调用
DragMove()
来响应MouseLeftButtonDown
(请参见Ross's answer)。问题在于,由于某种原因,如果窗口最大化,DragMove()
将无法正常工作,因此它不能与Windows 7 Aero Snap配合使用。由于我正在进行Windows 7集成,因此在我的情况下,这不是可接受的解决方案。