{"id":43,"date":"2010-03-08T19:18:00","date_gmt":"2010-03-08T19:18:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/davidrickard\/2010\/03\/08\/saving-window-size-and-location-in-wpf-and-winforms\/"},"modified":"2010-03-08T19:18:00","modified_gmt":"2010-03-08T19:18:00","slug":"saving-window-size-and-location-in-wpf-and-winforms","status":"publish","type":"post","link":"https:\/\/engy.us\/blog\/2010\/03\/08\/saving-window-size-and-location-in-wpf-and-winforms\/","title":{"rendered":"Saving window size and location in WPF and WinForms"},"content":{"rendered":"<p>A common user interface tweak is to save the size and location of a window and restore that state when the program starts up again. That way, the users don&rsquo;t need to re-do their work of resizing and moving the windows to where they want them. However I&rsquo;ve found that there isn&rsquo;t really a convenient way to do with in C#. Many solutions focus on recording the window width, height, x and y coordinates and current state (maximized, restored, etc), then applying all those values again on startup. But then you have to deal with edge cases: What if the user has changed resolutions since your program last ran? What if it was present on a monitor that&rsquo;s now disconnected?<\/p>\n<p>Fortunately, there are a couple of native Windows functions that can do all this work for us: <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms633544%28VS.85%29.aspx\">SetWindowPlacement<\/a> and <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms633518%28VS.85%29.aspx\">GetWindowPlacement<\/a>. MSDN has a <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/aa972163.aspx\">sample<\/a> demonstrating how to PInvoke to these functions in a WPF project, but it&rsquo;s got a few issues with it. For one, it&rsquo;s trying to store the placement as a custom type in settings, which can cause strange errors every time you open your Settings file. Here&rsquo;s my take on it:<\/p>\n<pre class=\"code\"><span style=\"color: blue;\">using <\/span>System;\n<span style=\"color: blue;\">using <\/span>System.IO;\n<span style=\"color: blue;\">using <\/span>System.Runtime.InteropServices;\n<span style=\"color: blue;\">using <\/span>System.Text;\n<span style=\"color: blue;\">using <\/span>System.Xml;\n<span style=\"color: blue;\">using <\/span>System.Xml.Serialization;\n\n<span style=\"color: blue;\">namespace <span style=\"color: #000000;\">WindowPlacementExample<\/span><\/span>\n{\n    <span style=\"color: green;\">\/\/ RECT structure required by WINDOWPLACEMENT structure\n    <\/span>[<span style=\"color: #2b91af;\">Serializable<\/span>]\n    [<span style=\"color: #2b91af;\">StructLayout<\/span>(<span style=\"color: #2b91af;\">LayoutKind<\/span>.Sequential)]\n    <span style=\"color: blue;\">public struct <\/span><span style=\"color: #2b91af;\">RECT\n    <\/span>{\n        <span style=\"color: blue;\">public int <\/span>Left;\n        <span style=\"color: blue;\">public int <\/span>Top;\n        <span style=\"color: blue;\">public int <\/span>Right;\n        <span style=\"color: blue;\">public int <\/span>Bottom;\n\n        <span style=\"color: blue;\">public <\/span>RECT(<span style=\"color: blue;\">int <\/span>left, <span style=\"color: blue;\">int <\/span>top, <span style=\"color: blue;\">int <\/span>right, <span style=\"color: blue;\">int <\/span>bottom)\n        {\n            <span style=\"color: blue;\">this<\/span>.Left = left;\n            <span style=\"color: blue;\">this<\/span>.Top = top;\n            <span style=\"color: blue;\">this<\/span>.Right = right;\n            <span style=\"color: blue;\">this<\/span>.Bottom = bottom;\n        }\n    }\n\n    <span style=\"color: green;\">\/\/ POINT structure required by WINDOWPLACEMENT structure\n    <\/span>[<span style=\"color: #2b91af;\">Serializable<\/span>]\n    [<span style=\"color: #2b91af;\">StructLayout<\/span>(<span style=\"color: #2b91af;\">LayoutKind<\/span>.Sequential)]\n    <span style=\"color: blue;\">public struct <\/span><span style=\"color: #2b91af;\">POINT\n    <\/span>{\n        <span style=\"color: blue;\">public int <\/span>X;\n        <span style=\"color: blue;\">public int <\/span>Y;\n\n        <span style=\"color: blue;\">public <\/span>POINT(<span style=\"color: blue;\">int <\/span>x, <span style=\"color: blue;\">int <\/span>y)\n        {\n            <span style=\"color: blue;\">this<\/span>.X = x;\n            <span style=\"color: blue;\">this<\/span>.Y = y;\n        }\n    }\n\n    <span style=\"color: green;\">\/\/ WINDOWPLACEMENT stores the position, size, and state of a window\n    <\/span>[<span style=\"color: #2b91af;\">Serializable<\/span>]\n    [<span style=\"color: #2b91af;\">StructLayout<\/span>(<span style=\"color: #2b91af;\">LayoutKind<\/span>.Sequential)]\n    <span style=\"color: blue;\">public struct <\/span><span style=\"color: #2b91af;\">WINDOWPLACEMENT\n    <\/span>{\n        <span style=\"color: blue;\">public int <\/span>length;\n        <span style=\"color: blue;\">public int <\/span>flags;\n        <span style=\"color: blue;\">public int <\/span>showCmd;\n        <span style=\"color: blue;\">public <\/span><span style=\"color: #2b91af;\">POINT <\/span>minPosition;\n        <span style=\"color: blue;\">public <\/span><span style=\"color: #2b91af;\">POINT <\/span>maxPosition;\n        <span style=\"color: blue;\">public <\/span><span style=\"color: #2b91af;\">RECT <\/span>normalPosition;\n    }\n\n    <span style=\"color: blue;\">public static class <\/span><span style=\"color: #2b91af;\">WindowPlacement\n    <\/span>{\n        <span style=\"color: blue;\">private static <\/span><span style=\"color: #2b91af;\">Encoding <\/span>encoding = <span style=\"color: blue;\">new <\/span><span style=\"color: #2b91af;\">UTF8Encoding<\/span>();\n        <span style=\"color: blue;\">private static <\/span><span style=\"color: #2b91af;\">XmlSerializer <\/span>serializer = <span style=\"color: blue;\">new <\/span><span style=\"color: #2b91af;\">XmlSerializer<\/span>(<span style=\"color: blue;\">typeof<\/span>(<span style=\"color: #2b91af;\">WINDOWPLACEMENT<\/span>));\n\n        [<span style=\"color: #2b91af;\">DllImport<\/span>(<span style=\"color: #a31515;\">\"user32.dll\"<\/span>)]\n        <span style=\"color: blue;\">private static extern bool <\/span>SetWindowPlacement(<span style=\"color: #2b91af;\">IntPtr <\/span>hWnd, [<span style=\"color: #2b91af;\">In<\/span>] <span style=\"color: blue;\">ref <\/span><span style=\"color: #2b91af;\">WINDOWPLACEMENT <\/span>lpwndpl);\n\n        [<span style=\"color: #2b91af;\">DllImport<\/span>(<span style=\"color: #a31515;\">\"user32.dll\"<\/span>)]\n        <span style=\"color: blue;\">private static extern bool <\/span>GetWindowPlacement(<span style=\"color: #2b91af;\">IntPtr <\/span>hWnd, <span style=\"color: blue;\">out <\/span><span style=\"color: #2b91af;\">WINDOWPLACEMENT <\/span>lpwndpl);\n\n        <span style=\"color: blue;\">private const int <\/span>SW_SHOWNORMAL = 1;\n        <span style=\"color: blue;\">private const int <\/span>SW_SHOWMINIMIZED = 2;\n\n        <span style=\"color: blue;\">public static void <\/span>SetPlacement(<span style=\"color: #2b91af;\">IntPtr <\/span>windowHandle, <span style=\"color: blue;\">string <\/span>placementXml)\n        {\n            <span style=\"color: blue;\">if <\/span>(<span style=\"color: blue;\">string<\/span>.IsNullOrEmpty(placementXml))\n            {\n                <span style=\"color: blue;\">return<\/span>;\n            }\n\n            <span style=\"color: #2b91af;\">WINDOWPLACEMENT <\/span>placement;\n            <span style=\"color: blue;\">byte<\/span>[] xmlBytes = encoding.GetBytes(placementXml);\n\n            <span style=\"color: blue;\">try\n            <\/span>{\n                <span style=\"color: blue;\">using <\/span>(<span style=\"color: #2b91af;\">MemoryStream <\/span>memoryStream = <span style=\"color: blue;\">new <\/span><span style=\"color: #2b91af;\">MemoryStream<\/span>(xmlBytes))\n                {\n                    placement = (<span style=\"color: #2b91af;\">WINDOWPLACEMENT<\/span>)serializer.Deserialize(memoryStream);\n                }\n\n                placement.length = <span style=\"color: #2b91af;\">Marshal<\/span>.SizeOf(<span style=\"color: blue;\">typeof<\/span>(<span style=\"color: #2b91af;\">WINDOWPLACEMENT<\/span>));\n                placement.flags = 0;\n                placement.showCmd = (placement.showCmd == SW_SHOWMINIMIZED ? SW_SHOWNORMAL : placement.showCmd);\n                SetWindowPlacement(windowHandle, <span style=\"color: blue;\">ref <\/span>placement);\n            }\n            <span style=\"color: blue;\">catch <\/span>(<span style=\"color: #2b91af;\">InvalidOperationException<\/span>)\n            {\n                <span style=\"color: green;\">\/\/ Parsing placement XML failed. Fail silently.\n            <\/span>}\n        }\n\n        <span style=\"color: blue;\">public static string <\/span>GetPlacement(<span style=\"color: #2b91af;\">IntPtr <\/span>windowHandle)\n        {\n            <span style=\"color: #2b91af;\">WINDOWPLACEMENT <\/span>placement = <span style=\"color: blue;\">new <\/span><span style=\"color: #2b91af;\">WINDOWPLACEMENT<\/span>();\n            GetWindowPlacement(windowHandle, <span style=\"color: blue;\">out <\/span>placement);\n\n            <span style=\"color: blue;\">using <\/span>(<span style=\"color: #2b91af;\">MemoryStream <\/span>memoryStream = <span style=\"color: blue;\">new <\/span><span style=\"color: #2b91af;\">MemoryStream<\/span>())\n            {\n                <span style=\"color: blue;\">using <\/span>(<span style=\"color: #2b91af;\">XmlTextWriter <\/span>xmlTextWriter = <span style=\"color: blue;\">new <\/span><span style=\"color: #2b91af;\">XmlTextWriter<\/span>(memoryStream, <span style=\"color: #2b91af;\">Encoding<\/span>.UTF8))\n                {\n                    serializer.Serialize(xmlTextWriter, placement);\n                    <span style=\"color: blue;\">byte<\/span>[] xmlBytes = memoryStream.ToArray();\n                    <span style=\"color: blue;\">return <\/span>encoding.GetString(xmlBytes);\n                }\n            }\n        }\n    }\n}<\/pre>\n<p>To get the placement of an existing window, you give it the native handle for the window, and get back a string of XML that represents the placement for the window. You save this string somewhere, then when the program starts back up again, apply it with SetPlacement. The above code works for both WinForms and WPF. And in both cases you can open your Properties\/Settings.settings file and add a new setting to store the string:<\/p>\n<p><a href=\"https:\/\/i1.wp.com\/msdnshared.blob.core.windows.net\/media\/TNBlogsFS\/BlogFileStorage\/blogs_msdn\/davidrickard\/WindowsLiveWriter\/SavingwindowsizeandlocationinWPFandWinFo_10F6C\/image_2.png?ssl=1\" original-url=\"http:\/\/blogs.msdn.com\/blogfiles\/davidrickard\/WindowsLiveWriter\/SavingwindowsizeandlocationinWPFandWinFo_10F6C\/image_2.png\"><img loading=\"lazy\" style=\"display: inline; border-width: 0px;\" title=\"image\" alt=\"image\" src=\"https:\/\/i2.wp.com\/msdnshared.blob.core.windows.net\/media\/TNBlogsFS\/BlogFileStorage\/blogs_msdn\/davidrickard\/WindowsLiveWriter\/SavingwindowsizeandlocationinWPFandWinFo_10F6C\/image_thumb.png?resize=445%2C93&#038;ssl=1\" original-url=\"http:\/\/blogs.msdn.com\/blogfiles\/davidrickard\/WindowsLiveWriter\/SavingwindowsizeandlocationinWPFandWinFo_10F6C\/image_thumb.png\" width=\"445\" border=\"0\" height=\"93\" data-recalc-dims=\"1\" \/><\/a> <\/p>\n<p>This will store the window state locally, per-user. Of course you could also store the string wherever you wanted to.<\/p>\n<p>What I like about this approach is that the WindowPlacement class does the XML serialization for you and gives you a nice, tidy string containing all the placement data.<\/p>\n<p>But where in the program code should we hook in to save and re-apply the window placements? The answer is a bit different between WinForms and WPF.<\/p>\n<p><strong>WPF:<\/strong><\/p>\n<p>You might benefit by throwing a couple of extension methods on the WindowPlacement class to make things a bit easier:<\/p>\n<pre class=\"code\"><span style=\"color: blue;\">public static void <\/span>SetPlacement(<span style=\"color: blue;\">this <\/span><span style=\"color: #2b91af;\">Window <\/span>window, <span style=\"color: blue;\">string <\/span>placementXml)\n{\n    <span style=\"color: #2b91af;\">WindowPlacement<\/span>.SetPlacement(<span style=\"color: blue;\">new <\/span><span style=\"color: #2b91af;\">WindowInteropHelper<\/span>(window).Handle, placementXml);\n}\n\n<span style=\"color: blue;\">public static string <\/span>GetPlacement(<span style=\"color: blue;\">this <\/span><span style=\"color: #2b91af;\">Window <\/span>window)\n{\n    <span style=\"color: blue;\">return <\/span><span style=\"color: #2b91af;\">WindowPlacement<\/span>.GetPlacement(<span style=\"color: blue;\">new <\/span><span style=\"color: #2b91af;\">WindowInteropHelper<\/span>(window).Handle);\n}<\/pre>\n<p>\n<a href=\"http:\/\/11011.net\/software\/vspaste\"><\/a><\/p>\n<p>To save the window placement, just handle the Closing event on the Window:<\/p>\n<pre class=\"code\"><span style=\"color: blue;\">private void <\/span>Window_Closing(<span style=\"color: blue;\">object <\/span>sender, <span style=\"color: #2b91af;\">CancelEventArgs <\/span>e)\n{\n    <span style=\"color: #2b91af;\">Settings<\/span>.Default.MainWindowPlacement = <span style=\"color: blue;\">this<\/span>.GetPlacement();\n    <span style=\"color: #2b91af;\">Settings<\/span>.Default.Save();\n}<\/pre>\n<p>To restore, you&rsquo;ll need to hook in on SourceInitialized:<\/p>\n<pre class=\"code\"><span style=\"color: blue;\">protected override void <\/span>OnSourceInitialized(<span style=\"color: #2b91af;\">EventArgs <\/span>e)\n{\n    <span style=\"color: blue;\">base<\/span>.OnSourceInitialized(e);\n    <span style=\"color: blue;\">this<\/span>.SetPlacement(<span style=\"color: #2b91af;\">Settings<\/span>.Default.MainWindowPlacement);\n}<\/pre>\n<p><strong>WinForms:<\/strong><\/p>\n<p>This one is a bit more straightforward. Save on the FormClosing event and restore the window state in the Load event handler. The Form&rsquo;s native handle is accessible from its Handle property.<\/p>\n<p>Now we have a robust and relatively painless way of persisting window sizes and positions, and we only need to keep track of one string per window.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>A common user interface tweak is to save the size and location of a window and restore that state when the program starts up again. That way, the users don&rsquo;t need to re-do their work of resizing and moving the windows to where they want them. However I&rsquo;ve found that there isn&rsquo;t really a convenient &hellip; <\/p>\n<p class=\"link-more\"><a href=\"https:\/\/engy.us\/blog\/2010\/03\/08\/saving-window-size-and-location-in-wpf-and-winforms\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Saving window size and location in WPF and WinForms&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"spay_email":"","jetpack_publicize_message":"","jetpack_is_tweetstorm":false},"categories":[1],"tags":[],"jetpack_featured_media_url":"","jetpack_publicize_connections":[],"jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/pahBcK-H","jetpack-related-posts":[{"id":120,"url":"https:\/\/engy.us\/blog\/2020\/01\/01\/implementing-a-custom-window-title-bar-in-wpf\/","url_meta":{"origin":43,"position":0},"title":"Implementing a Custom Window Title Bar in WPF","date":"January 1, 2020","format":false,"excerpt":"There are several good reasons for wanting custom window chrome in WPF, such as fitting in additional UI or implementing a Dark theme. However the actual implementation is kind of tricky, since it is now your job to provide a bunch of features that you used to get for free.\u2026","rel":"","context":"With 12 comments","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":174,"url":"https:\/\/engy.us\/blog\/2021\/12\/11\/aws-cognito-authentication-in-electron\/","url_meta":{"origin":43,"position":1},"title":"AWS Cognito Authentication in Electron","date":"December 11, 2021","format":false,"excerpt":"The AWS Cognito authentication service as of this writing does not officially support the Electron platform. But there is a Javascript SDK for Cognito, as part of AWS Amplify. Others have tried using it on Electron but have run into issues. I ran into several more than what are described\u2026","rel":"","context":"Similar post","img":{"alt_text":"","src":"https:\/\/i2.wp.com\/engy.us\/blog\/wp-content\/uploads\/2021\/12\/image.png?resize=350%2C200&ssl=1","width":350,"height":200},"classes":[]},{"id":88,"url":"https:\/\/engy.us\/blog\/2018\/10\/20\/dark-theme-in-wpf\/","url_meta":{"origin":43,"position":2},"title":"Dark Theme in WPF","date":"October 20, 2018","format":false,"excerpt":"In a recent Windows 10 update a toggle switch was added to allow the user to specify that they wanted \"Dark\" themes in apps: I decided to add support for this to VidCoder. But no updates to WPF were made to make this easy. WPF does having theming support where\u2026","rel":"","context":"With 5 comments","img":{"alt_text":"","src":"https:\/\/i2.wp.com\/engy.us\/blog\/wp-content\/uploads\/2018\/10\/VidCoderDarkExample.png?resize=350%2C200&ssl=1","width":350,"height":200},"classes":[]},{"id":51,"url":"https:\/\/engy.us\/blog\/2015\/07\/17\/installing-net-framework-4-5-automatically-with-inno-setup\/","url_meta":{"origin":43,"position":3},"title":"Installing .NET Framework 4.7 automatically with Inno Setup","date":"July 17, 2015","format":false,"excerpt":"In this guide I will walk through how to get the .NET framework to download and install on-the-fly in an Inno Setup installer. It works in 3 steps: Detect if the desired .NET framework is installed Download the .NET Framework bootstrap installer with Inno Download Plugin Run the bootstrap installer\u2026","rel":"","context":"In \".net framework 4.5 inno setup\"","img":{"alt_text":"","src":"https:\/\/i0.wp.com\/engy.us\/blog\/wp-content\/uploads\/2015\/07\/7028.InstallingFramework2-1.png?resize=350%2C200&ssl=1","width":350,"height":200},"classes":[]},{"id":146,"url":"https:\/\/engy.us\/blog\/2021\/02\/28\/installing-net-5-runtime-automatically-with-inno-setup\/","url_meta":{"origin":43,"position":4},"title":"Installing .NET 5 Runtime Automatically with Inno Setup","date":"February 28, 2021","format":false,"excerpt":"In this guide I will walk through how to get the .NET 5 runtime to download and install on-the-fly in an Inno Setup installer. It works in 3 steps: Detect if the desired .NET runtime is installedDownload the .NET Runtime bootstrap installer with Inno Download PluginRun the bootstrap installer in\u2026","rel":"","context":"With 2 comments","img":{"alt_text":"","src":"https:\/\/i0.wp.com\/engy.us\/blog\/wp-content\/uploads\/2021\/02\/image.png?resize=350%2C200&ssl=1","width":350,"height":200},"classes":[]},{"id":159,"url":"https:\/\/engy.us\/blog\/2021\/05\/25\/how-to-use-individual-code-signing-certificates-to-get-rid-of-smartscreen-warnings\/","url_meta":{"origin":43,"position":5},"title":"How to Use Individual Code Signing Certificates to get rid of SmartScreen warnings","date":"May 25, 2021","format":false,"excerpt":"The problem Windows SmartScreen has for a while been trying to keep malware at bay. One of the ways of doing that is putting up a big scary warning when you try to run anything they haven't validated as safe: You have to click \"More info\" then \"Run anyway\" to\u2026","rel":"","context":"With 5 comments","img":{"alt_text":"","src":"https:\/\/i2.wp.com\/engy.us\/blog\/wp-content\/uploads\/2021\/05\/image.png?resize=350%2C200&ssl=1","width":350,"height":200},"classes":[]}],"_links":{"self":[{"href":"https:\/\/engy.us\/blog\/wp-json\/wp\/v2\/posts\/43"}],"collection":[{"href":"https:\/\/engy.us\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/engy.us\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/engy.us\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/engy.us\/blog\/wp-json\/wp\/v2\/comments?post=43"}],"version-history":[{"count":0,"href":"https:\/\/engy.us\/blog\/wp-json\/wp\/v2\/posts\/43\/revisions"}],"wp:attachment":[{"href":"https:\/\/engy.us\/blog\/wp-json\/wp\/v2\/media?parent=43"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/engy.us\/blog\/wp-json\/wp\/v2\/categories?post=43"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/engy.us\/blog\/wp-json\/wp\/v2\/tags?post=43"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}