添加项目文件。
This commit is contained in:
359
DragDropHelper.cs
Normal file
359
DragDropHelper.cs
Normal file
@@ -0,0 +1,359 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Shapes;
|
||||
using WinForms = System.Windows.Forms;
|
||||
|
||||
namespace DrillTools
|
||||
{
|
||||
/// <summary>
|
||||
/// 拖放帮助类
|
||||
/// </summary>
|
||||
public static class DragDropHelper
|
||||
{
|
||||
private static System.Windows.Point _startPoint;
|
||||
private static bool _isDragging;
|
||||
private static DragToolTipWindow? _dragToolTipWindow;
|
||||
private static Window? _ownerWindow;
|
||||
private static System.Windows.Shapes.Rectangle? _insertionIndicator;
|
||||
private static int _insertionIndex = -1;
|
||||
private static DateTime? _lastUpdateTime;
|
||||
|
||||
/// <summary>
|
||||
/// 启用 ListView 的拖放功能
|
||||
/// </summary>
|
||||
/// <typeparam name="T">数据项类型</typeparam>
|
||||
/// <param name="listView">ListView 控件</param>
|
||||
/// <param name="insertionIndicator">插入位置指示器</param>
|
||||
public static void EnableDragDrop<T>(System.Windows.Controls.ListView listView, System.Windows.Shapes.Rectangle insertionIndicator) where T : class
|
||||
{
|
||||
_insertionIndicator = insertionIndicator;
|
||||
_ownerWindow = Window.GetWindow(listView);
|
||||
|
||||
listView.PreviewMouseLeftButtonDown += (sender, e) =>
|
||||
{
|
||||
_startPoint = e.GetPosition(null);
|
||||
_isDragging = false;
|
||||
};
|
||||
|
||||
listView.PreviewMouseMove += (sender, e) =>
|
||||
{
|
||||
if (e.LeftButton == MouseButtonState.Pressed && !_isDragging)
|
||||
{
|
||||
System.Windows.Point position = e.GetPosition(null);
|
||||
if (Math.Abs(position.X - _startPoint.X) > SystemParameters.MinimumHorizontalDragDistance ||
|
||||
Math.Abs(position.Y - _startPoint.Y) > SystemParameters.MinimumVerticalDragDistance)
|
||||
{
|
||||
_isDragging = true;
|
||||
var listViewItem = FindAncestor<System.Windows.Controls.ListViewItem>((DependencyObject)e.OriginalSource);
|
||||
if (listViewItem != null)
|
||||
{
|
||||
var item = listView.ItemContainerGenerator.ItemFromContainer(listViewItem) as T;
|
||||
if (item != null)
|
||||
{
|
||||
// 获取屏幕坐标
|
||||
var screenPosition = listView.PointToScreen(e.GetPosition(listView));
|
||||
|
||||
// 创建并显示拖动提示
|
||||
CreateDragToolTip(item, screenPosition);
|
||||
|
||||
// 使用 QueryContinueDrag 事件来更新位置
|
||||
System.Windows.QueryContinueDragEventHandler queryContinueHandler = null;
|
||||
queryContinueHandler = (sender, e) =>
|
||||
{
|
||||
if (_dragToolTipWindow != null)
|
||||
{
|
||||
// 获取当前鼠标位置
|
||||
var currentPos = WinForms.Control.MousePosition;
|
||||
_dragToolTipWindow.UpdatePosition(new System.Windows.Point(currentPos.X, currentPos.Y));
|
||||
}
|
||||
|
||||
// 如果拖放结束,移除事件处理
|
||||
if (e.Action == System.Windows.DragAction.Drop || e.Action == System.Windows.DragAction.Cancel)
|
||||
{
|
||||
DragDrop.RemoveQueryContinueDragHandler(listView, queryContinueHandler);
|
||||
}
|
||||
};
|
||||
|
||||
DragDrop.AddQueryContinueDragHandler(listView, queryContinueHandler);
|
||||
|
||||
System.Windows.DataObject data = new System.Windows.DataObject(typeof(T), item);
|
||||
DragDrop.DoDragDrop(listViewItem, data, System.Windows.DragDropEffects.Move);
|
||||
|
||||
// 清理拖动提示
|
||||
CleanupDragToolTip();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
listView.DragOver += (sender, e) =>
|
||||
{
|
||||
if (e.Data.GetDataPresent(typeof(T)))
|
||||
{
|
||||
e.Effects = System.Windows.DragDropEffects.Move;
|
||||
|
||||
// 更新插入位置指示器
|
||||
UpdateInsertionIndicator(listView, e.GetPosition(listView));
|
||||
}
|
||||
else
|
||||
{
|
||||
e.Effects = System.Windows.DragDropEffects.None;
|
||||
}
|
||||
e.Handled = true;
|
||||
};
|
||||
|
||||
listView.DragLeave += (sender, e) =>
|
||||
{
|
||||
HideInsertionIndicator();
|
||||
};
|
||||
|
||||
listView.Drop += (sender, e) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
// 隐藏插入指示器
|
||||
HideInsertionIndicator();
|
||||
|
||||
Debug.WriteLine($"[DragDrop] Drop事件触发 - OriginalSource类型: {e.OriginalSource?.GetType().Name}");
|
||||
Debug.WriteLine($"[DragDrop] Drop位置: ({e.GetPosition(listView).X}, {e.GetPosition(listView).Y})");
|
||||
|
||||
if (e.Data.GetDataPresent(typeof(T)))
|
||||
{
|
||||
var droppedItem = e.Data.GetData(typeof(T)) as T;
|
||||
if (droppedItem != null)
|
||||
{
|
||||
Debug.WriteLine($"[DragDrop] 拖放项: {droppedItem}");
|
||||
|
||||
// 检查是否是机台码刀具,如果是则不允许移动
|
||||
if (droppedItem is ToolItem toolItem && toolItem.ToolType == ToolType.MachineCode)
|
||||
{
|
||||
Debug.WriteLine("[DragDrop] 机台码刀具不允许移动");
|
||||
System.Windows.MessageBox.Show("机台码刀具不允许移动位置", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
_isDragging = false;
|
||||
return;
|
||||
}
|
||||
|
||||
var targetItem = FindAncestor<System.Windows.Controls.ListViewItem>((DependencyObject)e.OriginalSource);
|
||||
string ss = targetItem == null ? "NULL" : "找到";
|
||||
Debug.WriteLine($"[DragDrop] 目标ListViewItem: {ss}");
|
||||
|
||||
if (targetItem == null)
|
||||
{
|
||||
Debug.WriteLine("[DragDrop] 警告: 目标项为空,可能是拖放到列表外部");
|
||||
_isDragging = false;
|
||||
return;
|
||||
}
|
||||
|
||||
var targetIndex = listView.ItemContainerGenerator.IndexFromContainer(targetItem);
|
||||
Debug.WriteLine($"[DragDrop] 目标索引: {targetIndex}");
|
||||
|
||||
var sourceIndex = listView.Items.IndexOf(droppedItem);
|
||||
Debug.WriteLine($"[DragDrop] 源索引: {sourceIndex}");
|
||||
|
||||
// 检查目标位置是否是机台码刀具
|
||||
var viewModel = listView.DataContext as MainWindowViewModel;
|
||||
if (viewModel != null && viewModel.Tools.Count > targetIndex)
|
||||
{
|
||||
var targetTool = viewModel.Tools[targetIndex];
|
||||
if (targetTool.ToolType == ToolType.MachineCode)
|
||||
{
|
||||
Debug.WriteLine("[DragDrop] 不能移动到机台码刀具位置");
|
||||
System.Windows.MessageBox.Show("不能移动到机台码刀具位置", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
_isDragging = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (sourceIndex != -1 && targetIndex != -1 && sourceIndex != targetIndex)
|
||||
{
|
||||
viewModel?.ReorderTools(sourceIndex, targetIndex);
|
||||
Debug.WriteLine($"[DragDrop] 重新排序完成: {sourceIndex} -> {targetIndex}");
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.WriteLine($"[DragDrop] 跳过重新排序 - 源索引: {sourceIndex}, 目标索引: {targetIndex}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine($"[DragDrop] 异常: {ex.GetType().Name} - {ex.Message}");
|
||||
Debug.WriteLine($"[DragDrop] 堆栈跟踪: {ex.StackTrace}");
|
||||
System.Windows.MessageBox.Show($"拖放操作发生错误: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_isDragging = false;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找指定类型的父元素
|
||||
/// </summary>
|
||||
/// <typeparam name="T">父元素类型</typeparam>
|
||||
/// <param name="current">当前元素</param>
|
||||
/// <returns>找到的父元素,如果未找到则返回 null</returns>
|
||||
private static T? FindAncestor<T>(DependencyObject current) where T : DependencyObject
|
||||
{
|
||||
Debug.WriteLine($"[FindAncestor] 开始查找类型 {typeof(T).Name},起始元素类型: {current?.GetType().Name ?? "NULL"}");
|
||||
int depth = 0;
|
||||
|
||||
while (current != null)
|
||||
{
|
||||
Debug.WriteLine($"[FindAncestor] 深度 {depth}: 当前类型 {current.GetType().Name}");
|
||||
|
||||
if (current is T ancestor)
|
||||
{
|
||||
Debug.WriteLine($"[FindAncestor] 找到匹配的祖先类型 {typeof(T).Name}");
|
||||
return ancestor;
|
||||
}
|
||||
|
||||
current = VisualTreeHelper.GetParent(current);
|
||||
depth++;
|
||||
|
||||
if (depth > 10) // 防止无限循环
|
||||
{
|
||||
Debug.WriteLine("[FindAncestor] 警告: 搜索深度超过10层,停止搜索");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Debug.WriteLine($"[FindAncestor] 未找到类型 {typeof(T).Name} 的祖先");
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 处理主窗口鼠标移动事件,更新拖动提示位置
|
||||
/// </summary>
|
||||
private static void OnOwnerWindowMouseMove(object sender, System.Windows.Input.MouseEventArgs e)
|
||||
{
|
||||
if (_dragToolTipWindow != null && _isDragging)
|
||||
{
|
||||
// 获取屏幕坐标
|
||||
var windowPosition = e.GetPosition(_ownerWindow);
|
||||
var screenPosition = _ownerWindow.PointToScreen(windowPosition);
|
||||
_dragToolTipWindow.UpdatePosition(screenPosition);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建拖动提示窗口
|
||||
/// </summary>
|
||||
private static void CreateDragToolTip<T>(T item, System.Windows.Point position) where T : class
|
||||
{
|
||||
if (item is ToolItem toolItem && _ownerWindow != null)
|
||||
{
|
||||
_dragToolTipWindow = new DragToolTipWindow();
|
||||
_dragToolTipWindow.SetToolInfo(toolItem);
|
||||
_dragToolTipWindow.UpdatePosition(position);
|
||||
// 不设置 Owner,这样窗口可以独立定位
|
||||
_dragToolTipWindow.Show();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清理拖动提示窗口
|
||||
/// </summary>
|
||||
private static void CleanupDragToolTip()
|
||||
{
|
||||
if (_dragToolTipWindow != null)
|
||||
{
|
||||
_dragToolTipWindow.Close();
|
||||
_dragToolTipWindow = null;
|
||||
}
|
||||
|
||||
if (_ownerWindow != null)
|
||||
{
|
||||
_ownerWindow.MouseMove -= OnOwnerWindowMouseMove;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新插入位置指示器
|
||||
/// </summary>
|
||||
private static void UpdateInsertionIndicator(System.Windows.Controls.ListView listView, System.Windows.Point position)
|
||||
{
|
||||
if (_insertionIndicator == null) return;
|
||||
|
||||
// 使用节流机制,避免过于频繁的更新
|
||||
if (_lastUpdateTime != null && DateTime.Now - _lastUpdateTime < TimeSpan.FromMilliseconds(16))
|
||||
return;
|
||||
|
||||
_lastUpdateTime = DateTime.Now;
|
||||
|
||||
try
|
||||
{
|
||||
// 使用 VisualTreeHelper 找到鼠标下的元素
|
||||
var element = listView.InputHitTest(position) as DependencyObject;
|
||||
var listViewItem = FindAncestor<System.Windows.Controls.ListViewItem>(element);
|
||||
|
||||
if (listViewItem != null)
|
||||
{
|
||||
var index = listView.ItemContainerGenerator.IndexFromContainer(listViewItem);
|
||||
var itemBounds = listViewItem.TransformToAncestor(listView)
|
||||
.TransformBounds(new Rect(0, 0, listViewItem.ActualWidth, listViewItem.ActualHeight));
|
||||
|
||||
// 判断是在上半部分还是下半部分
|
||||
bool insertAfter = position.Y > itemBounds.Top + itemBounds.Height / 2;
|
||||
int targetIndex = insertAfter ? index + 1 : index;
|
||||
|
||||
if (targetIndex != _insertionIndex)
|
||||
{
|
||||
_insertionIndex = targetIndex;
|
||||
|
||||
// 更新指示器位置
|
||||
_insertionIndicator.Visibility = Visibility.Visible;
|
||||
|
||||
// 计算指示器位置
|
||||
double indicatorTop = insertAfter ? itemBounds.Bottom : itemBounds.Top;
|
||||
|
||||
// 使用 VerticalAlignment 和 Margin 结合来定位指示器
|
||||
_insertionIndicator.VerticalAlignment = VerticalAlignment.Top;
|
||||
_insertionIndicator.Margin = new Thickness(0, indicatorTop, 0, 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 如果没有找到目标项,检查是否在列表末尾
|
||||
if (position.Y > listView.ActualHeight - 20)
|
||||
{
|
||||
_insertionIndex = listView.Items.Count;
|
||||
// 在列表末尾显示指示器
|
||||
_insertionIndicator.Visibility = Visibility.Visible;
|
||||
_insertionIndicator.VerticalAlignment = VerticalAlignment.Top;
|
||||
_insertionIndicator.Margin = new Thickness(0, listView.ActualHeight - 2, 0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
HideInsertionIndicator();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine($"[DragDrop] 更新插入指示器时发生错误: {ex.Message}");
|
||||
HideInsertionIndicator();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 隐藏插入位置指示器
|
||||
/// </summary>
|
||||
private static void HideInsertionIndicator()
|
||||
{
|
||||
if (_insertionIndicator != null)
|
||||
{
|
||||
_insertionIndicator.Visibility = Visibility.Collapsed;
|
||||
}
|
||||
_insertionIndex = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user