Shawn Roser
Shawn Roser

Reputation: 467

How do I set a draggable wpf popup to its original location once it is closed?

I used code found here on Stack Overflow to make a WPF popup draggable using attached behavors. This code and behavior works as expected. The popup will remain at its dragged position until the user moves it again.

What I want to do now is make the popup appear at its original placement target location once it is closed and reopened. How do I accomplish this task?

Original post: A draggable popup control in wpf

Answer code written by Rick Sladkey: https://stackoverflow.com/a/4784977/1286413

Here is the XAML for the Popup:

<Grid>
   <StackPanel>
       <TextBox x:Name="textBox1" Width="200" Height="20"/>
   </StackPanel>
   <Popup PlacementTarget="{Binding ElementName=textBox1}" IsOpen="{Binding IsKeyboardFocused, ElementName=textBox1, Mode=OneWay}">
       <i:Interaction.Behaviors>
           <local:MouseDragPopupBehavior/>
       </i:Interaction.Behaviors>
       <TextBlock Background="White">
           <TextBlock.Text>Sample Popup content.</TextBlock.Text>
       </TextBlock>
   </Popup>
</Grid>

Here is the AttachedBehavior he wrote:

public class MouseDragPopupBehavior : Behavior<Popup>
{
   private bool mouseDown;
   private Point oldMousePosition;

   protected override void OnAttached()
   {
       AssociatedObject.MouseLeftButtonDown += (s, e) =>
       {
           mouseDown = true;
           oldMousePosition = AssociatedObject.PointToScreen(e.GetPosition(AssociatedObject));
           AssociatedObject.Child.CaptureMouse();
       };
       AssociatedObject.MouseMove += (s, e) =>
       {
           if (!mouseDown) return;
           var newMousePosition = AssociatedObject.PointToScreen(e.GetPosition(AssociatedObject));
           var offset = newMousePosition - oldMousePosition;
           oldMousePosition = newMousePosition;
           AssociatedObject.HorizontalOffset += offset.X;
           AssociatedObject.VerticalOffset += offset.Y;
       };
       AssociatedObject.MouseLeftButtonUp += (s, e) =>
       {
           mouseDown = false;
           AssociatedObject.Child.ReleaseMouseCapture();
       };
   }
}

Thanks in advance for the help!

Upvotes: 2

Views: 1685

Answers (1)

ChimeraObscura
ChimeraObscura

Reputation: 1964

In OnAttached, add a handler to Closed that will save the popup's position, and another handler to Opened that will move the popup back to that position.

public class MouseDragPopupBehavior : Behavior<Popup>
{
    private bool mouseDown;
    private Point oldMousePosition;

    private bool useSavedPosition;
    private Point savedPosition;

    protected override void OnAttached()
    {
        AssociatedObject.MouseLeftButtonDown += (s, e) =>
        {
            mouseDown = true;
            oldMousePosition = AssociatedObject.PointToScreen(e.GetPosition(AssociatedObject));
            AssociatedObject.Child.CaptureMouse();
        };
        AssociatedObject.MouseMove += (s, e) =>
        {
            if (!mouseDown) return;
            var newMousePosition = AssociatedObject.PointToScreen(e.GetPosition(AssociatedObject));
            var offset = newMousePosition - oldMousePosition;
            oldMousePosition = newMousePosition;
            AssociatedObject.HorizontalOffset += offset.X;
            AssociatedObject.VerticalOffset += offset.Y;
        };
        AssociatedObject.MouseLeftButtonUp += (s, e) =>
        {
            mouseDown = false;
            AssociatedObject.Child.ReleaseMouseCapture();
        };

        AssociatedObject.Opened += (s, e) =>
        {
            if (!useSavedPosition) return;
            AssociatedObject.HorizontalOffset = savedPosition.X;
            AssociatedObject.VerticalOffset = savedPosition.Y;
        };

        AssociatedObject.Loaded += (s, e) =>
        {
            savedPosition = new Point(AssociatedObject.HorizontalOffset, AssociatedObject.VerticalOffset);
            useSavedPosition = true;
        };
    }
}

Upvotes: 2

Related Questions