窗口没有奇怪的行为,相反,窗口有两个奇怪的行为。
"[...] 当窗口最大化时,我无法从屏幕顶部边缘附近的最后一个像素拖动窗口 [...]"
这个行为是因为当窗口变为最大化状态时,边框调整大小的边缘仍然处于活动状态。实际上,这个边缘总是活动的。通过设置ResizeBorderThickness属性,WindowChrome保留了那么多像素来控制调整窗口大小的行为。鉴于在最大化模式下不允许调整大小事件,你会注意到这些像素不允许任何类型的行为。这正是因为WindowChrome专门保留了控制调整大小行为的那些像素。
解决方案是什么?需要通知WindowChrome在窗口最大化时将ResizeBorderThickness属性改为0。这可以通过在xaml中再次设置WindowChrome触发器来简单完成:
<Trigger Property="WindowState" Value="Maximized">
<Setter Property="WindowChrome.WindowChrome">
<Setter.Value>
<WindowChrome ResizeBorderThickness="0" [...] />
</Setter.Value>
</Setter>
</Trigger>
注意:此功能也可以在运行时代码中完成。
"[...] 如果我将 WindowChrome 的 ResizeBorderThickness 设置为 <= 7,一切正常 [...] 而每超过 7 个像素,我就必须从边缘向下拖动多一个像素。 [...]"
请注意:这种行为并不是由于设置了 ResizeBorderThickness,而是由于设置了属性 WindowStyle=None。当设置了此属性时,窗口在最大化时会表现出奇怪的行为:
窗口的左上角不位于当前屏幕的点 (0,0),而是会变得异常负数(在您的情况下,在 Y 轴上的值似乎为 -7)。
窗口的大小取决于当前屏幕的尺寸,而正常行为应该是窗口的大小取决于当前屏幕的工作区域(当前屏幕除任务栏等之外的部分)。
这种带有窗口的奇怪行为使得当前屏幕上没有显示出预留给“WindowChrome”的 7 个像素(显然,当 ResizeBorderThickness="7" 时),因此您会感觉到属性 ResizeBorderThickness="7" 工作正常,但实际上不是这样。事实上,这解释了当 ResizeBorderThickness 的值为 8 或更高时的表现。
解决方案是什么? 在最大化时需要强制窗口大小和位置与当前屏幕的工作区域相同。警告:如果只针对主屏幕进行操作,则对多个屏幕的最大化事件无法正常工作。
解决此问题的代码可以通过调用外部 API 来解决:
[DllImport("user32")]
internal static extern bool GetMonitorInfo(IntPtr hMonitor, MONITORINFO lpmi);
[DllImport("user32")]
internal static extern IntPtr MonitorFromWindow(IntPtr handle, int flags);
定义类和结构:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto, Pack = 4)]
public class MONITORINFO
{
public int cbSize = Marshal.SizeOf(typeof(MONITORINFO));
public RECT rcMonitor = new RECT();
public RECT rcWork = new RECT();
public int dwFlags = 0;
}
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int left;
public int top;
public int right;
public int bottom;
}
[StructLayout(LayoutKind.Sequential)]
public struct POINT
{
public int x;
public int y;
public POINT(int x, int y) { this.x = x; this.y = y; }
}
[StructLayout(LayoutKind.Sequential)]
public struct MINMAXINFO
{
public POINT ptReserved;
public POINT ptMaxSize;
public POINT ptMaxPosition;
public POINT ptMinTrackSize;
public POINT ptMaxTrackSize;
}
最后定义添加钩子 WndProc 到窗口的函数:
public static void CompatibilityMaximizedNoneWindow(Window window)
private static System.IntPtr CompatibilityMaximizedNoneWindowProc(
System.IntPtr hwnd,
int msg,
System.IntPtr wParam,
System.IntPtr lParam,
ref bool handled)
Marshal.StructureToPtr(mmi, lParam, true);
handled = true;
break;
}
return (System.IntPtr)0;
}
使用CompatibilityMaximizedNoneWindow API,您可以在窗口的构造函数中轻松调用该API,如下所示:
public MyWindow
{
[...]
MyNamespace.CompatibilityMaximizedNoneWindow(this);
}
第二个奇怪的行为必须解决。您会注意到,在代码中工作时,必须添加引用PresentationFramework和命名空间System.Windows.Interop。