WPF鼠标拖拽的最佳实现

WPF鼠标拖拽的最佳实现

在很多项目中都会遇到鼠标拖拽控件移动的需求,常见的有从在列表中拖拽列表项移动,拖拽控件移动等。

本文将介绍2种拖拽的简单的实现

列表项的拖拽

本文将使用 gong-wpf-dragdrop 这个github上的库来实现列表的拖拽的效果,项目地址
优点非常简单,几行代码就可以实现效果了。

1.先看最终效果

在这里插入图片描述

2.实现过程

  1. 在Neget中搜索并安装gong-wpf-dragdrop库

    在这里插入图片描述

  2. 在需要拖拽的列表控件上添加代码

            <ListBox
                x:Name="MyListBox"
                dd:DragDrop.DropHandler="{Binding}"
                dd:DragDrop.DropTargetAdornerBrush="{DynamicResource PrimaryThemeColor}"
                dd:DragDrop.IsDragSource="True"
                dd:DragDrop.IsDropTarget="True"
                dd:DragDrop.UseDefaultDragAdorner="True"
                ItemsSource="{Binding PipeList}"
                SelectionChanged="ListBox_SelectionChanged">
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <Border Height="40">
                            <Grid Background="Transparent">
                                <TextBlock VerticalAlignment="Center" Text="{Binding}" />
                            </Grid>
                        </Border>
                    </DataTemplate>
                </ListBox.ItemTemplate>
        </ListBox>
    

    并且引入命名空间

    xmlns:dd="urn:gong-wpf-dragdrop"
    

    此时就能看到列表已经可以被拖拽排序了

    在这里插入图片描述

    此时会有一点小瑕疵,那就是预览项并不会出现在鼠标点下的位置,而是在光标的上边,这时需要通过 DragAdornerTranslation 属性来控制偏移,实现一个更好的拾起效果,在列表中添加事件SelectionChanged 代码如下:

            private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
            {
    
                // 获取当前选中项的ListBoxItem
                ListBoxItem selectedItem = (ListBoxItem)MyListBox.ItemContainerGenerator.ContainerFromItem(MyListBox.SelectedItem);
    
                if (selectedItem != null)
                {
                    // 获取鼠标相对于当前选中项的位置
                    Point position = Mouse.GetPosition(selectedItem);
    
                    // 偏移鼠标相对于当前选中项的位置
                    GongSolutions.Wpf.DragDrop.DragDrop.SetDragAdornerTranslation(MyListBox, new Point(-position.X, position.Y));//= "10,10"
    
                }
        	}
    

    最终就实现了我们需要的效果

    在这里插入图片描述

控件的拖拽

控件的拖拽移动比较简单,就是直接使用代码实现了,主要会用到鼠标的三个事件

  • PreviewMouseDown 鼠标按下
  • PreviewMouseMove 鼠标移动
  • PreviewMouseUp 鼠标抬起

先看效果

在这里插入图片描述

实现过程

通过TranslateTransform来实现更改控件的位置,通过鼠标按下事件中,记录的按下时的鼠标坐标,和控件当前坐标,通过鼠标 移动事件中,鼠标位置偏移量,还原到控件上,就实现了这个效果,代码如下

xaml文件代码:

          <Button
              Width="120"
              Height="40"
              Content="Test"
              PreviewMouseDown="Button_PreviewMouseDown"
              PreviewMouseMove="Button_PreviewMouseMove"
              PreviewMouseUp="Button_PreviewMouseUp" />

cs代码:

public bool isMouseDown = false;
public Point mouseDownPosition;
public Point mouseDownControlPosition;
private void Button_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
    isMouseDown = true;

    var ctl = sender as UIElement;
    mouseDownPosition = e.GetPosition(null);

    var transform = ctl.RenderTransform as TranslateTransform;
    if (transform == null)
    {
        transform = new TranslateTransform();
        ctl.RenderTransform = transform;
    }
    mouseDownControlPosition = new Point(transform.X, transform.Y);
    ctl.CaptureMouse();
}

private void Button_PreviewMouseMove(object sender, MouseEventArgs e)
{
    if (isMouseDown)
    {
        var button = (UIElement)sender;
        TranslateTransform transform = button.RenderTransform as TranslateTransform;
        Point currentPoint = e.GetPosition(null);
        double offsetX = currentPoint.X - mouseDownPosition.X;
        double offsetY = currentPoint.Y - mouseDownPosition.Y;

        double newX = mouseDownControlPosition.X + offsetX;
        double newY = mouseDownControlPosition.Y + offsetY;

        transform.X = newX;
        transform.Y = newY;
    }
}

private void Button_PreviewMouseUp(object sender, MouseButtonEventArgs e)
{
    var ctl = sender as UIElement;
    isMouseDown = false;
    ctl.ReleaseMouseCapture();
}

这样就实现了控件移动的效果

在这里插入图片描述

实现鼠标拖拽改变Rectangle大小以及旋转,可以使用WPF的MVVMLight框架来实现。 首先,在ViewModel中定义Rectangle的位置、大小和角度等属性,以及鼠标拖拽的事件处理函数。 ``` public class MainViewModel : ViewModelBase { private double _left; private double _top; private double _width; private double _height; private double _angle; public double Left { get { return _left; } set { Set(ref _left, value); } } public double Top { get { return _top; } set { Set(ref _top, value); } } public double Width { get { return _width; } set { Set(ref _width, value); } } public double Height { get { return _height; } set { Set(ref _height, value); } } public double Angle { get { return _angle; } set { Set(ref _angle, value); } } public void OnMouseDown(object sender, MouseButtonEventArgs e) { // 鼠标按下时记录鼠标位置 } public void OnMouseMove(object sender, MouseEventArgs e) { // 鼠标移动时根据鼠标位置计算Rectangle的位置、大小和角度 } public void OnMouseUp(object sender, MouseButtonEventArgs e) { // 鼠标抬起时清空鼠标位置记录 } } ``` 接着,在View中使用MVVMLight框架提供的Binding绑定属性和事件处理函数。 ``` <Window.DataContext> <vm:MainViewModel /> </Window.DataContext> <Grid> <Rectangle Fill="Blue" Width="{Binding Width}" Height="{Binding Height}" Canvas.Left="{Binding Left}" Canvas.Top="{Binding Top}" RenderTransformOrigin="0.5,0.5"> <Rectangle.RenderTransform> <RotateTransform Angle="{Binding Angle}" /> </Rectangle.RenderTransform> <i:Interaction.Triggers> <i:EventTrigger EventName="MouseDown"> <i:InvokeCommandAction Command="{Binding MouseDownCommand}" /> </i:EventTrigger> <i:EventTrigger EventName="MouseMove"> <i:InvokeCommandAction Command="{Binding MouseMoveCommand}" /> </i:EventTrigger> <i:EventTrigger EventName="MouseUp"> <i:InvokeCommandAction Command="{Binding MouseUpCommand}" /> </i:EventTrigger> </i:Interaction.Triggers> </Rectangle> </Grid> ``` 最后,在ViewModel中实现鼠标拖拽事件处理函数,计算Rectangle的位置、大小和角度。 ``` public RelayCommand MouseDownCommand { get; private set; } public RelayCommand MouseMoveCommand { get; private set; } public RelayCommand MouseUpCommand { get; private set; } public MainViewModel() { MouseDownCommand = new RelayCommand(OnMouseDown); MouseMoveCommand = new RelayCommand(OnMouseMove); MouseUpCommand = new RelayCommand(OnMouseUp); } private Point _lastMousePosition; public void OnMouseDown() { _lastMousePosition = Mouse.GetPosition(Application.Current.MainWindow); } public void OnMouseMove() { if (Mouse.LeftButton == MouseButtonState.Pressed) { var currentMousePosition = Mouse.GetPosition(Application.Current.MainWindow); var delta = currentMousePosition - _lastMousePosition; _lastMousePosition = currentMousePosition; // 计算Rectangle的位置、大小和角度 } } public void OnMouseUp() { _lastMousePosition = new Point(); } ``` 这样就可以通过MVVMLight框架实现鼠标拖拽改变Rectangle大小以及旋转了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值