【发布时间】:2011-07-26 11:24:28
【问题描述】:
在 Windows Explorer 和 Internet Explorer 等应用程序中,可以抓住标题栏下方的扩展框架区域并拖动窗口。
对于 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,哪些不应该?我正在考虑使用Points 来检查我的控件位置的点击位置,但我不确定如何在 WPF 领域进行。
编辑 [4/24]: 一种简单的方法是让一个不可见的控件,甚至是窗口本身,通过在窗口上调用 DragMove() 来响应 MouseLeftButtonDown(参见Ross's answer)。问题是由于某种原因DragMove() 在窗口最大化时不起作用,因此它不能很好地与 Windows 7 Aero Snap 配合使用。由于我打算进行 Windows 7 集成,因此在我的情况下这不是一个可接受的解决方案。
【问题讨论】:
-
这个问题包括一个关于在 C# 中处理 windows 消息的简短教程,它有精心制作的插图,准确地指出了所要求的内容,并且没有明显的拼写错误。 +1,宝贝!
-
@Jeffrey L Whitledge:哎呀,谢谢(+1 给你)!最后我必须编辑的一件事是问题标题......我发誓以前的标题不是我在发布之前写的。
标签: c# .net wpf winapi windows-7