Drag WPF Popup control

≯℡__Kan透↙ 提交于 2019-11-28 18:22:02

Here's a simple solution using a Thumb.

  • Subclass Popup in XAML and codebehind
  • Add a Thumb with width/height set to 0 (this could also be done in XAML)
  • Listen for MouseDown events on the Popup and raise the same event on the Thumb
  • Move popup on DragDelta

XAML:

<Popup x:Class="PopupTest.DraggablePopup" ...>
    <Canvas x:Name="ContentCanvas">

    </Canvas>
</Popup>

C#:

public partial class DraggablePopup : Popup 
{
    public DraggablePopup()
    {
        var thumb = new Thumb
        {
            Width = 0,
            Height = 0,
        };
        ContentCanvas.Children.Add(thumb);

        MouseDown += (sender, e) =>
        {
            thumb.RaiseEvent(e);
        };

        thumb.DragDelta += (sender, e) =>
        {
            HorizontalOffset += e.HorizontalChange;
            VerticalOffset += e.VerticalChange;
        };
    }
}

There is no DragMove for PopUp. Just a small work around, there is lot of improvements you can add to this.

<Popup x:Name="pop" IsOpen="True" Height="200" Placement="AbsolutePoint"  Width="200">
   <Rectangle Stretch="Fill" Fill="Red"/>            
</Popup>

In the code behind , add this mousemove event

   pop.MouseMove += new MouseEventHandler(pop_MouseMove);

   void pop_MouseMove(object sender, MouseEventArgs e)
    {
        if (e.LeftButton == MouseButtonState.Pressed)
        {
            pop.PlacementRectangle = new Rect(new Point(e.GetPosition(this).X,
                e.GetPosition(this).Y),new Point(200,200));

        }
    }

Another way of achieving this is to set your Popup's placement to MousePoint. This makes the popup initially appear at the position of the mouse cursor.

Then you can either use a Thumb or MouseMove event to set the Popup's HorizontalOffset & VerticalOffset. These properties shift the Popup away from its original position as the user drags it.

Remember to reset HorizontalOffset and VerticalOffset back to zero for the next use of the popup!

Leon

The issue with loosing the mouse when moving too fast, could be resolved


This is taken from msdn:

The new window contains the Child content of Popup.

The Popup control maintains a reference to its Child content as a logical child. When the new window is created, the content of Popup becomes a visual child of the window and remains the logical child of Popup. Conversely, Popup remains the logical parent of its Child content.


In the other words, the child of the popup is displayed in standalone window.

So when trying to the following:
Popup.CaptureMouse() is capturing the wrapper window and not the popup itself. Instead using Popup.Child.CaptureMouse() captures the actual popup.

And all other events should be registered using Popup.Child.

Like Popup.Child.MouseMove, Popup.Child.LostCapture and so on

This has been tested and works perfectly fine

Private Point startPoint;

 private void Window_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {

        startPoint = e.GetPosition(null);
    }
private void Window_MouseMove(object sender, MouseEventArgs e)
    {
        if (e.LeftButton == MouseButtonState.Pressed)
        {
            Point relative = e.GetPosition(null);
            Point AbsolutePos = new Point(relative.X + this.Left, relative.Y + this.Top);
            this.Top = AbsolutePos.Y - startPoint.Y;
            this.Left = AbsolutePos.X - startPoint.X;
        }
    }

This works for dragging my window, but like it was told if i move the mouse to fast, it would get out of window and stop raising the event. Without mentioning the dragging is not smooth at all. Does anyone knows how to do it properly, nice and smooth dragging, without loosing it when dragged too fast??? Post a simple example if possible, other than a whole tutorial that would get beginners like me lost in code. Thanks!

Building off of Jobi Joy's answer, I found a re-useable solution that allows you to add as a control within xaml of an existing control/page. Which was not possible adding as Xaml with a Name since it has a different scope.

    [ContentProperty("Child")]
    [DefaultEvent("Opened")]
    [DefaultProperty("Child")]
    [Localizability(LocalizationCategory.None)]
    public class DraggablePopup : Popup
    {
        public DraggablePopup()
        {
            MouseDown += (sender, e) =>
            {
                Thumb.RaiseEvent(e);
            };

            Thumb.DragDelta += (sender, e) =>
            {
                HorizontalOffset += e.HorizontalChange;
                VerticalOffset += e.VerticalChange;
            };
        }

        /// <summary>
        /// The original child added via Xaml
        /// </summary>
        public UIElement TrueChild { get; private set; }

        public Thumb Thumb { get; private set; } = new Thumb
        {
            Width = 0,
            Height = 0,
        };

        protected override void OnInitialized(EventArgs e)
        {
            base.OnInitialized(e);

            TrueChild = Child;

            var surrogateChild = new StackPanel();

            RemoveLogicalChild(TrueChild);

            surrogateChild.Children.Add(Thumb);
            surrogateChild.Children.Add(TrueChild);

            AddLogicalChild(surrogateChild);
            Child = surrogateChild;
        }
    }
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!