在WPF中创建一个可移动的控件

8

我有一个面板,在这个面板中有几个矩形控件(控件数量不定)。我希望用户能够在面板内移动这些控件,以便他们可以按照自己的喜好排列控件。有没有什么资源或简单的技巧可以让我朝着正确的方向前进呢?

谢谢。

2个回答

10

我找到了一种可能的简单方法,实现控件的拖动/移动...下面是具体步骤:

  1. 选择你希望成为移动区域的控件元素。当用户按住鼠标时,控件将在此区域内移动。在我的情况下,它是控件顶部的一个矩形边框。
  2. 使用OnMouseDown事件将布尔值(在我的情况下是IsMoving)设置为true,使用MouseUp事件将其设置为false
  3. 在第一次MouseDown事件中,使用以下代码设置某个点属性(InitialPosition):

  4. if (FirstClick)
    {
         GeneralTransform transform = this.TransformToAncestor(this.Parent as Visual);
         Point StartPoint = transform.Transform(new Point(0, 0));
         StartX = StartPoint.X;
         StartY = StartPoint.Y;
         FirstClick = false;
    }
    
    现在你已经有了起始位置,需要获取鼠标相对于移动控件的位置。这是为了防止你点击标题中间来移动它,导致控件的左上角瞬间移动到鼠标指针位置。为了做到这一点,在MouseDown事件中使用以下代码:
    Point RelativeMousePoint = Mouse.GetPosition(Header);
    RelativeX = RelativeMousePoint.X;
    RelativeY = RelativeMousePoint.Y;
    
    现在,您已经拥有了控件起始点(startX和startY)以及鼠标在移动控件中的位置(RelativeX、RelativeY),我们只需将控件移动到新位置!这涉及到几个步骤。首先,您的控件需要具有一个RenderTransform,它是一个TranslateTransform。如果您不想在XAML中设置它,请使用this.RenderTransform = new TranslateTransform进行设置。
    现在,我们需要在RenderTransform上设置X和Y坐标,以便控件移动到新位置。以下代码可以实现此目的:
    private void Header_MouseMove(object sender, MouseEventArgs e)
    {
        if (IsMoving)
        {
            //Get the position of the mouse relative to the controls parent              
            Point MousePoint = Mouse.GetPosition(this.Parent as IInputElement );
            //set the distance from the original position
            this.DistanceFromStartX= MousePoint.X - StartX - RelativeX ;
            this.DistanceFromStartY= MousePoint.Y - StartY - RelativeY;
            //Set the X and Y coordinates of the RenderTransform to be the Distance from original position. This will move the control
            TranslateTransform MoveTransform = base.RenderTransform as TranslateTransform;
            MoveTransform.X = this.DistanceFromStartX;
            MoveTransform.Y = this.DistanceFromStartY;
        }
    }
    

可以猜到,还有一些代码被省略了(变量声明等),但这应该足以帮助你入门了 :) 祝你编码愉快。

编辑:
一个可能会遇到的问题是这样可以让控件脱离其父控件的范围。下面是一些快速而不太规范的代码来解决这个问题...

if ((MousePoint.X + this.Width - RelativeX > Parent.ActualWidth) ||
     MousePoint.Y + this.Height - RelativeY > Parent.ActualHeight ||
     MousePoint.X - RelativeX  < 0 || 
     MousePoint.Y - RelativeY  < 0)
{
    IsMoving = false;
    return;
}

在实际移动发生之前,将此代码放在鼠标移动事件中。这将检查控件是否试图移动到父控件的边界外。IsMoving = false命令将导致控件退出移动模式。这意味着用户需要再次单击移动区域来尝试移动控件,因为它已经停止在边界上。如果您希望控件自动继续移动,请将该行删除,控件将在回到合法区域后立即跳回到光标上。


顺便提一下,如果用户移动鼠标太快,控件将失去移动焦点。 - TerrorAustralis

4

确实可以从中获得很多灵感。虽然不完全符合我的要求,但我不想接受我的答案,这帮助我重构了我的代码。 :) - TerrorAustralis
1
顺便说一下,@TerrorAustralis,接受自己的答案完全没有问题。 - ANeves

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接