WPF:通过捕获鼠标事件来使Canvas中的所有控件都动起来

原文地址: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,现在所有控件都可以被移动了:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值