How can I move a WPF Popup when its anchor element moves?

Mizipzor picture Mizipzor · Oct 21, 2009 · Viewed 54.1k times · Source

I have a Popup defined like this:

<Popup
    Name="myPopup"
    StaysOpen="True"
    Placement="Bottom"
    PlacementRectangle="0,20,0,20"
    PlacementTarget="{Binding ElementName=myPopupAnchor}">
    <TextBlock ... />
</Popup>

I have added event handlers to the myPopupAnchor element for the events MouseEnter and MouseLeave. The two event handlers toggle the popup's visibility.

My problem is the position of myPopupAnchor is only read when the popup is first shown, or hidden and then shown again. If the anchor moves, the popup does not.

I'm looking for ways to work around this, I want a moving Popup. Can I notify WPF that the PlacementTarget binding has changed and should be read again? Can I manually set the popup's position?

Currently, I have a very crude workaround that involves closing and then opening the popup again, which causes some repainting issues.

Answer

NathanAW picture NathanAW · Mar 17, 2010

I looked at a couple options and samples out there. The thing that seems to work best for me is to "bump" one of the properties that causes the Popup to reposition itself on its own. The property that I used is HorizontalOffset.

I set it to (itself + 1) and then set it back the original value. I do this in an event handler that runs when the window is repositioned.

// Reference to the PlacementTarget.
DependencyObject myPopupPlacementTarget;

// Reference to the popup.
Popup myPopup; 

Window w = Window.GetWindow(myPopupPlacementTarget);
if (null != w)
{
    w.LocationChanged += delegate(object sender, EventArgs args)
    {
        var offset = myPopup.HorizontalOffset;
        myPopup.HorizontalOffset = offset + 1;
        myPopup.HorizontalOffset = offset;
    };
}

When the window is moved, the popup will reposition. The subtle change in the HorizontalOffset is not noticed because the window and popup are already moving anyway.

I'm still evaluating whether a popup control is the best option in cases where the control stays open during other interaction. I'm thinking that Ray Burns suggestion to put this stuff in an Adorner layer seems like a good approach for some scenarios.