{"id":2647,"date":"2014-11-27T22:38:48","date_gmt":"2014-11-27T22:38:48","guid":{"rendered":"http:\/\/putridparrot.com\/blog\/?p=2647"},"modified":"2014-11-28T09:39:02","modified_gmt":"2014-11-28T09:39:02","slug":"automatically-update-a-wpf-popup-position","status":"publish","type":"post","link":"https:\/\/putridparrot.com\/blog\/automatically-update-a-wpf-popup-position\/","title":{"rendered":"Automatically update a WPF Popup position"},"content":{"rendered":"<p>I wanted a means to automatically reposition a popup in relation to it&#8217;s placement target &#8211; for example I created a popup that was displayed to the right of another control (the placement target), but when the control&#8217;s parent window moved the popup (by default) does not move with it &#8211; I needed it to reposition in relation to the placement target. <\/p>\n<p>So I&#8217;ve implemented the following behavior to automatically reposition the popup when the parent window is moved<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\npublic class AutoRepositionPopupBehavior : Behavior&lt;Popup&gt;\r\n{\r\n   private const int WM_MOVING = 0x0216;\r\n\r\n   \/\/ should be moved to a helper class\r\n   private DependencyObject GetTopmostParent(DependencyObject element)\r\n   {\r\n      var current = element;\r\n      var result = element;\r\n\r\n      while (current != null)\r\n      {\r\n         result = current;\r\n         current = (current is Visual || current is Visual3D) ? \r\n            VisualTreeHelper.GetParent(current) :\r\n            LogicalTreeHelper.GetParent(current);\r\n      }\r\n      return result;\r\n   }\r\n\r\n   protected override void OnAttached()\r\n   {\r\n      base.OnAttached();\r\n\r\n      AssociatedObject.Loaded += (sender, e) =&gt;\r\n      {\r\n         var root = GetTopmostParent(AssociatedObject.PlacementTarget) as Window;\r\n         if (root != null)\r\n         {\r\n            var helper = new WindowInteropHelper(root);\r\n            var hwndSource = HwndSource.FromHwnd(helper.Handle);\r\n            if (hwndSource != null)\r\n            {\r\n               hwndSource.AddHook(HwndMessageHook);\r\n            }\r\n         }\r\n      };\r\n   }\r\n\r\n   private IntPtr HwndMessageHook(IntPtr hWnd, \r\n           int msg, IntPtr wParam, \r\n           IntPtr lParam, ref bool bHandled)\r\n   {\r\n      if (msg == WM_MOVING)\r\n      {\r\n         Update();\t\t\t\t\r\n      }\r\n      return IntPtr.Zero;\r\n   }\r\n\r\n   public void Update()\r\n   {\r\n      \/\/ force the popup to update it's position\r\n      var mode = AssociatedObject.Placement;\r\n      AssociatedObject.Placement = PlacementMode.Relative;\r\n      AssociatedObject.Placement = mode;\r\n   }\r\n}\r\n<\/pre>\n<p>So to use the above code we simple use the following XAML within a popup element<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\n&lt;i:Interaction.Behaviors&gt;\r\n   &lt;behaviors:AutoRepositionPopupBehavior \/&gt;\r\n&lt;\/i:Interaction.Behaviors&gt;\r\n<\/pre>\n<p>When the AssociatedObject is loaded we locate the topmost window hosting the AssociatedObject and then we hook into the message queue watching for the Window WM_MOVEING message. On each WM_MOVEING message, we update the placement of the popup. To get the Popup to recalculate its position we need to change the placement to something other than what it&#8217;s set as, i.e. it needs to change. Then when we reset the placement to our original placement, the Popup position is recalculated.<\/p>\n<p>This code could be improved by checking the Placement and ensuring it changes &#8211; in the code above I simply set to PlacementMode.Relative because I know my code a different PlacementMode. Also the above code does not handle the Popup repositioning in the PlacementRectangle is used. Also my requirement doesn&#8217;t include the resizing of the PlacementTarget.<\/p>\n<p>I&#8217;ll leave those changes until I need them&#8230;<\/p>\n<p><strong>Update<\/strong><\/p>\n<p>Seems I did need to handle resizing of the PlacementTarget so I&#8217;ve now added the following to the OnAttached method<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nAssociatedObject.LayoutUpdated += (sender, e) =&gt; Update();\r\n<\/pre>\n<p>and that appears to solve that problem.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I wanted a means to automatically reposition a popup in relation to it&#8217;s placement target &#8211; for example I created a popup that was displayed to the right of another control (the placement target), but when the control&#8217;s parent window moved the popup (by default) does not move with it &#8211; I needed it to [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[13],"tags":[],"class_list":["post-2647","post","type-post","status-publish","format-standard","hentry","category-wpf"],"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/2647","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/comments?post=2647"}],"version-history":[{"count":6,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/2647\/revisions"}],"predecessor-version":[{"id":2667,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/2647\/revisions\/2667"}],"wp:attachment":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/media?parent=2647"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/categories?post=2647"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/tags?post=2647"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}