【发布时间】:2013-10-05 21:40:42
【问题描述】:
我正在我的 WPF 应用程序中调用 SetWindowPlacement 以保存和恢复窗口位置。这很好用,但是当窗口是工具窗口而不是标准窗口时,确保窗口永远不会完全隐藏的宣传能力似乎不起作用。您使用负的 Left 和 Right 展示位置调用 SetWindowPlacement,它会很高兴地在屏幕外打开它,而无法重新打开它。
有没有办法让 SetWindowPlacement 更正这些工具窗口的位置(对于缺少的监视器等)?
如果做不到这一点,有没有好的手动方法呢?供参考,代码:
// RECT structure required by WINDOWPLACEMENT structure
[Serializable]
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
public RECT(int left, int top, int right, int bottom)
{
this.Left = left;
this.Top = top;
this.Right = right;
this.Bottom = bottom;
}
}
// POINT structure required by WINDOWPLACEMENT structure
[Serializable]
[StructLayout(LayoutKind.Sequential)]
public struct POINT
{
public int X;
public int Y;
public POINT(int x, int y)
{
this.X = x;
this.Y = y;
}
}
// WINDOWPLACEMENT stores the position, size, and state of a window
[Serializable]
[StructLayout(LayoutKind.Sequential)]
public struct WINDOWPLACEMENT
{
public int length;
public int flags;
public int showCmd;
public POINT minPosition;
public POINT maxPosition;
public RECT normalPosition;
}
public static class WindowPlacement
{
private static Encoding encoding = new UTF8Encoding();
private static XmlSerializer serializer = new XmlSerializer(typeof(WINDOWPLACEMENT));
[DllImport("user32.dll")]
private static extern bool SetWindowPlacement(IntPtr hWnd, [In] ref WINDOWPLACEMENT lpwndpl);
[DllImport("user32.dll")]
private static extern bool GetWindowPlacement(IntPtr hWnd, out WINDOWPLACEMENT lpwndpl);
private const int SW_SHOWNORMAL = 1;
private const int SW_SHOWMINIMIZED = 2;
public static void SetPlacement(IntPtr windowHandle, string placementXml)
{
if (string.IsNullOrEmpty(placementXml))
{
return;
}
WINDOWPLACEMENT placement;
byte[] xmlBytes = encoding.GetBytes(placementXml);
try
{
using (MemoryStream memoryStream = new MemoryStream(xmlBytes))
{
placement = (WINDOWPLACEMENT)serializer.Deserialize(memoryStream);
}
placement.length = Marshal.SizeOf(typeof(WINDOWPLACEMENT));
placement.flags = 0;
placement.showCmd = (placement.showCmd == SW_SHOWMINIMIZED ? SW_SHOWNORMAL : placement.showCmd);
SetWindowPlacement(windowHandle, ref placement);
}
catch (InvalidOperationException)
{
// Parsing placement XML failed. Fail silently.
}
}
public static string GetPlacement(IntPtr windowHandle)
{
WINDOWPLACEMENT placement = new WINDOWPLACEMENT();
GetWindowPlacement(windowHandle, out placement);
using (MemoryStream memoryStream = new MemoryStream())
{
using (XmlTextWriter xmlTextWriter = new XmlTextWriter(memoryStream, Encoding.UTF8))
{
serializer.Serialize(xmlTextWriter, placement);
byte[] xmlBytes = memoryStream.ToArray();
return encoding.GetString(xmlBytes);
}
}
}
}
使用顶部:200,底部:600,左侧:-1000,右侧:-300 调用 SetPlacement。
【问题讨论】:
-
在 WINDOWPLACEMENT 的 MSDN 文章中有非常明确的警告,说明工作区和屏幕坐标之间的差异以及工具窗口的不同之处。没什么可看的,所以我只能假设您以某种方式弄错了。不要对您的代码保密。
-
工作空间和屏幕坐标之间的差异不是这里的问题。我附上了代码,但问题的核心是在一个工具窗口上调用 SetPlacement,该工具窗口的正常放置 RECT 位于正常屏幕区域之外。
-
实际上您不需要显式的 XML 序列化:您可以按原样将 WINDOWPLACEMENT 的实例存储在设置中。顺便说一句,如果它目前在可见区域之外,则 WIndows 7 似乎会调整位置。否则,感谢您分享您的代码!
-
@Vlad 当您尝试按原样保存设置 UI 时,它的行为很奇怪。同样在我的情况下,我不使用内置设置保存它;我存储在一个 sqlite 数据库中。另外当你看到它在可视区域之外调整窗口的位置时,你使用的是普通窗口还是工具窗口?
-
@RandomEngy:我没有注意到 VS 2019 的设置有任何奇怪的行为。数据库当然是另一回事。