原文地址:https://www.mgenware.com/blog/wp-content/uploads/2012/03/201203301315305256.png
曾经写过一篇文章:WPF:实现一个很简单的设计器(移动和缩放控件),讲了使用WPF中的Adorner来修饰Canvas中的元素从而使它们可以被移动或者缩放。今天讲通过原始事件的方法来使Canvas中的元素可以被移动。
首先就是定义一个Canvas,然后定义Canvas中的控件。接着使用MouseMove,MouseDown,MouseUp这三个Bubble类型的路由事件。我们将会在之后填充这三个事件。
XAML定义:
<Canvas Name="canvas"
PreviewMouseMove="canvas_MouseMove"
PreviewMouseDown="canvas_MouseDown"
PreviewMouseUp="canvas_MouseUp">
<Ellipse Fill="GreenYellow"
Width="50"
Height="50"
Canvas.Left="10"
Canvas.Top="10"/>
<Rectangle Fill="Orange"
Width="100"
Height="40"
Canvas.Left="100"
Canvas.Top="50"/>
<Button Canvas.Left="100"
Canvas.Top="10"
Content="A"/>
<TextBox Canvas.Left="130"
Canvas.Top="20"
Width="100"
Text="Mgen"/>
</Canvas>
接下来,我们使用一种最原始的方法,首先在MouseDown事件中通过Mouse.DirectlyOver属性确定鼠标指向的Canvas中的控件,然后存下来控件和鼠标点击位置的偏移量,最后在MouseMove事件中设置控件更新的位置,这样控件就被移动了。当然,由于使用原始的鼠标点击事件,对于某些控件比如:Button、TextBox……由于它们对鼠标事件处理的特殊性,所以下面的代码无法移动上述控件(文章下面会给出更好的处理方式)
如下代码:
//选中控件的鼠标位置偏移量
Point targetPoint;
//选中控件
UIElement targetElement;
private void canvas_MouseDown(object sender, MouseButtonEventArgs e)
{
//确定选中控件,然后设置选中控件
targetElement = Mouse.DirectlyOver as UIElement;
if (targetElement != null)
targetPoint = e.GetPosition(targetElement);
}
private void canvas_MouseUp(object sender, MouseButtonEventArgs e)
{
//鼠标松开后,将选中控件设置成null
targetElement = null;
}
private void canvas_MouseMove(object sender, MouseEventArgs e)
{
//确定鼠标左键处于按下状态并且有元素被选中
if (e.LeftButton == MouseButtonState.Pressed && targetElement != null)
{
var pCanvas = e.GetPosition(canvas);
//设置最终位置
Canvas.SetLeft(targetElement, pCanvas.X - targetPoint.X);
Canvas.SetTop(targetElement, pCanvas.Y - targetPoint.Y);
}
}
上面讲过,上述代码对于大多数控件都表现良好,但是对于某些对鼠标事件有依赖的控件会无法移动,所以我们使用另一种优化的方法,通过使用捕获鼠标事件来移动控件。
捕获鼠标通过UIElement.CaptureMouse方法,捕获鼠标后,即使鼠标不在控件上,相应的鼠标事件仍会被控件接受。取消捕获鼠标可以使用Mouse.Capture(null)方法,或者UIElement.ReleaseMouseCapture方法。
代码:(XAML不变)
//选中控件的鼠标位置偏移量
Point targetPoint;
private void canvas_MouseDown(object sender, MouseButtonEventArgs e)
{
var targetElement = e.Source as IInputElement;
if (targetElement != null)
{
targetPoint = e.GetPosition(targetElement);
//开始捕获鼠标
targetElement.CaptureMouse();
}
}
private void canvas_MouseUp(object sender, MouseButtonEventArgs e)
{
//取消捕获鼠标
Mouse.Capture(null);
}
private void canvas_MouseMove(object sender, MouseEventArgs e)
{
//确定鼠标左键处于按下状态并且有元素被选中
var targetElement = Mouse.Captured as UIElement;
if (e.LeftButton == MouseButtonState.Pressed && targetElement != null)
{
var pCanvas = e.GetPosition(canvas);
//设置最终位置
Canvas.SetLeft(targetElement, pCanvas.X - targetPoint.X);
Canvas.SetTop(targetElement, pCanvas.Y - targetPoint.Y);
}
}
OK,现在所有控件都可以被移动了: