拖动WPF弹出控件

时间:2008-10-21 14:13:24

标签: c# .net wpf xaml popup

WPF Popup控件很不错,但在我看来有些局限。有没有办法在打开时“拖动”弹出窗口(就像使用Windows的DragMove()方法一样)?

这可以在没有大问题的情况下完成,还是我必须自己编写弹出类的替代品? 感谢

7 个答案:

答案 0 :(得分:17)

PopUp没有DragMove。只是一个小小的工作,你可以添加很多改进。

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

在后面的代码中,添加此mousemove事件

   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));

        }
    }

答案 1 :(得分:14)

这是使用Thumb的简单解决方案。

  • XAML中的子类Popup和codebehind
  • 添加一个宽度/高度设置为0的拇指(这也可以在XAML中完成)
  • 在Popup上侦听MouseDown事件并在Thumb
  • 上引发相同的事件
  • 在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;
        };
    }
}

答案 2 :(得分:2)

实现此目的的另一种方法是将Popup的位置设置为MousePoint。这使弹出窗口最初出现在鼠标光标的位置。

然后你可以使用Thumb或MouseMove事件来设置Popup的Horizo​​ntalOffset&amp; VerticalOffset。当用户拖动Popup时,这些属性会将Popup从原始位置移开。

请记住将Horizo​​ntalOffset和VerticalOffset重置为零,以便下次使用弹出窗口!

答案 3 :(得分:2)

移动太快时松动鼠标的问题可以解决


这取自msdn:

  

新窗口包含Popup的Child内容。

     

Popup控件将其Child内容的引用维护为逻辑子项。创建新窗口时,Popup的内容将成为窗口的可视子项,并仍然是Popup的逻辑子项。相反,Popup仍然是其子内容的逻辑父母。


换句话说,弹出窗口的子窗口显示在独立窗口中。

因此,当尝试以下内容时:
Popup.CaptureMouse()正在捕获包装器窗口,而不是弹出窗口本身。而是使用Popup.Child.CaptureMouse()捕获实际的弹出窗口。

所有其他事件都应使用Popup.Child注册。

Popup.Child.MouseMovePopup.Child.LostCapture等相似

这已经过测试,效果非常好

答案 4 :(得分:1)

与其他人对此的说法相反,我 100% 同意 Jobi Joy 的回答(老实说,这应该是公认的答案)。我看到一条评论说答案中的解决方案会导致内存碎片。这是不可能的,因为创建新结构根本不会导致内存碎片;事实上,使用结构体可以节省内存,因为它们是堆栈分配的。此外,我认为这实际上是重新定位弹出窗口的正确方法(毕竟,微软出于某种原因添加了 PlacementRectangle 属性),因此它不是黑客。然而,附加 Thumbs 并期望用户始终将 Popup 放置在画布上是非常笨拙的,而且并不总是一个实用的解决方案。

答案 5 :(得分:0)

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;
        }
    }

这适用于拖动我的窗口,但就像它被告知如果我将鼠标移动到快速,它将离开窗口并停止提升事件。没有提到拖拽根本不顺利。有没有人知道如何正确地做,漂亮和平滑的拖动,而不是在拖得太快时失去它???如果可能的话,发布一个简单的例子,除了整个教程,让像我这样的初学者在代码中丢失。谢谢!

答案 6 :(得分:0)

基于Jobi Joy的答案,我找到了可重用的解决方案,该解决方案使您可以在现有控件/页面的xaml中添加为控件。由于它具有不同的作用域,因此无法将它添加为带有名称的Xaml。

    [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;
        }
    }