WPF鼠标拖拽的最佳实现
在很多项目中都会遇到鼠标拖拽控件移动的需求,常见的有从在列表中拖拽列表项移动,拖拽控件移动等。
本文将介绍2种拖拽的简单的实现
列表项的拖拽
本文将使用 gong-wpf-dragdrop
这个github上的库来实现列表的拖拽的效果,项目地址
优点非常简单,几行代码就可以实现效果了。
1.先看最终效果
2.实现过程
-
在Neget中搜索并安装gong-wpf-dragdrop库
-
在需要拖拽的列表控件上添加代码
<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();
}
这样就实现了控件移动的效果