1
0
mirror of https://github.com/fadden/6502bench.git synced 2024-08-14 18:28:57 +00:00
6502bench/CommonWPF/WindowPlacement.cs
Andy McFadden 96a92f0335 Load/save app settings
This change pulls in the settings file code, which is mostly
unchanged except when it comes to saving and restoring the window
location and size.

The old system has been replaced with a PInvoke-based version that
calls the underlying Win32 window placement code.  This is more
likely to be correct when multiple displays are in use, and can
record the un-maximized size of a maximized window.  It leaves a
nasty XML string embedded in the config file, but it's not really
meant to be human-readable anyway.

The sub-window dividers all work completely differently from the way
they did in WinForms, and some of the behavior is a bit obscure
(like noticing when a splitter moves due to keyboard input, and
setting the position in a way that doesn't break the auto-sizing).
Yay WPF.

Still need to preserve column widths.
2019-06-19 18:09:55 -07:00

127 lines
4.4 KiB
C#

/*
* This comes from "David Rickard's Tech Blog", posted by RandomEngy on March 8 2010:
* https://blogs.msdn.microsoft.com/davidrickard/2010/03/08/saving-window-size-and-location-in-wpf-and-winforms/
*
* Saving and restoring a window's size and position can be tricky when there are multiple
* displays involved. This uses the Win32 system functions to do the job properly and
* consistently. (In theory.)
*
* The code works for WinForms (save on FormClosing, restore on Load, using the native handle
* from the Handle property) and WPF (use the Window extension methods in Closing and
* SourceInitialized). Besides convenience, it has the added benefit of being able to
* capture the non-maximized values for a maximized window.
*/
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows;
using System.Windows.Interop;
using System.Xml;
using System.Xml.Serialization;
namespace CommonWPF {
// 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);
}
}
}
//
// Extension methods for WPF.
//
public static string GetPlacement(this Window window) {
return GetPlacement(new WindowInteropHelper(window).Handle);
}
public static void SetPlacement(this Window window, string placementXml) {
SetPlacement(new WindowInteropHelper(window).Handle, placementXml);
}
}
}