在学习过程中,做了个Demo,分享一下,做的比较粗糙,若有不对希望哥哥们指出来
首先说说前台样式:
样式比较简单主要就是两个控件listview和Popup ,这个Popup主要是用来实时显示当前操作的item放在哪里了,粗线表示放在哪个地方,这是效果图:
后台主要就是拖拽的事件,不算复杂,相关的属性,方法都在下面了,可以直接用
#region Property
Grid lastUnderLine;
Grid lastTopLine;
bool isMovingUpward;
// 声明全局变量保存拖动开始的位置
private Point dragStartPosition;
DataObject lastData = null;
Stopwatch stopWatch = new Stopwatch();
delegate Point GetPositionDelegate(IInputElement element);
#endregion Property
#region DropEvent
private void ListItem_DragOver(object sender, DragEventArgs e)
{
myPopup.IsOpen = true;
if (!myPopup.IsOpen)
{
myPopup.IsOpen = true;
}
Size popupSize = new Size(100, 32);
var popupPoint = e.GetPosition(ListDemo);
popupPoint.X += 20; // 显示Popup的位置离鼠标X方向偏移50
myPopup.PlacementRectangle = new Rect(popupPoint, popupSize);
}
// 拖动开始时的事件处理程序
private void ListItem_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
// 记录拖动开始的位置
dragStartPosition = e.GetPosition(ListDemo);
}
// 拖动进入时的事件处理程序
private void ListItem_DragEnter(object sender, DragEventArgs e)
{
// 先将所有分割线不可见
if (lastUnderLine != null)
{
lastUnderLine.Visibility = Visibility.Collapsed;
}
if (lastTopLine != null)
{
lastTopLine.Visibility = Visibility.Collapsed;
}
// 获取当前鼠标位置
Point currentMousePosition = e.GetPosition(ListDemo);
// 再将拖拽所在的分割线可见
var row = GetListViewItemFromPoint(ListDemo, currentMousePosition);
// 判断鼠标相对于拖动开始的位置是向上还是向下
isMovingUpward = currentMousePosition.Y < dragStartPosition.Y;
// 根据方向显示相应的分割线
if (isMovingUpward)
{
// 向上移动,显示 topLine
if (row != null)
{
Grid topLine = FindVisualChild(row, "topLine");
topLine.Visibility = Visibility.Visible;
lastTopLine = topLine;
}
}
else
{
// 向下移动,显示 underLine
if (row != null)
{
Grid underLine = FindVisualChild(row, "underLine");
underLine.Visibility = Visibility.Visible;
lastUnderLine = underLine;
}
}
}
//监测鼠标事件
private void ListItem_MouseMove(object sender, MouseEventArgs e)
{
try
{
ListView listview = sender as ListView;
if (e.LeftButton == MouseButtonState.Pressed)
{
System.Collections.IList list = listview.SelectedItems as System.Collections.IList;
DataObject data = new DataObject(typeof(System.Collections.IList), list);
if (list.Count > 0 && lastData != data)
{
lastData = data;
DragDrop.DoDragDrop(listview, data, DragDropEffects.Move);
}
}
if ((e.LeftButton == MouseButtonState.Released && ListDemo.SelectedItems.Count > 0) || (stopWatch.ElapsedMilliseconds > 5000 && ListDemo.SelectedItems.Count > 0))//鼠标离开释放Drop锁定 & 未锁定情况下不释放
{
stopWatch.Stop();
ListDemo.SelectedItems.Clear();
}
}
catch (Exception)
{
}
}
//拖动完成事件
private void ListItem__Drop(object sender, DragEventArgs e)
{
try
{
List LevelsTemp = new List();
if (e.Data.GetDataPresent(typeof(System.Collections.IList)))
{
System.Collections.IList peopleList = e.Data.GetData(typeof(System.Collections.IList)) as System.Collections.IList;
//index为放置时鼠标下元素项的索引
int newIndex = GetCurrentIndex(new GetPositionDelegate(e.GetPosition));
ListDemo old = peopleList[0] as ListDemo;
int oldIndex = old.Index;
LevelsTemp = new List();
foreach (var item in this._page1Vm.ListDemos)
{
ListDemo levelConfig = new ListDemo()
{
Index = item.Index,
Name = item.Name,
Descripton = item.Descripton,
};
if (item.Index == oldIndex)
{
levelConfig.Index = newIndex;
}
else if (oldIndex > newIndex && item.Index >= newIndex && item.Index < oldIndex)
{
levelConfig.Index = item.Index + 1;
}
else if (oldIndex < newIndex && item.Index > oldIndex && item.Index <= newIndex)
{
levelConfig.Index = item.Index - 1;
}
LevelsTemp.Add(levelConfig);
}
LevelsTemp.Sort((x, y) => x.Index.CompareTo(y.Index));
this._page1Vm.ListDemos = LevelsTemp;
}
// 先将所有分割线不可见
if (lastUnderLine != null)
{
lastUnderLine.Visibility = Visibility.Collapsed;
}
if (lastTopLine != null)
{
lastTopLine.Visibility = Visibility.Collapsed;
}
myPopup.IsOpen = false;
}
catch (Exception) { }
finally
{
stopWatch.Stop();
}
}
#endregion DropEvent
#region Tool Method
private ListViewItem GetListViewItemFromPoint(ListView listView, Point point)
{
// 使用 HitTest 获取鼠标点击位置的 HitTestResult
HitTestResult hitTestResult = VisualTreeHelper.HitTest(listView, point);
if (hitTestResult != null)
{
// 获取 HitTestResult 的 VisualHit(也就是命中的可视元素)
DependencyObject target = hitTestResult.VisualHit;
// 在 Visual 树中向上查找
while (target != null && !(target is ListViewItem))
{
target = VisualTreeHelper.GetParent(target);
}
return target as ListViewItem;
}
return null;
}
// 在 视觉树中查找具有特定类型和名称的子元素
private T FindVisualChild(DependencyObject parent, string name) where T : DependencyObject
{
int count = VisualTreeHelper.GetChildrenCount(parent);
for (int i = 0; i < count; i++)
{
var child = VisualTreeHelper.GetChild(parent, i);
if (child is T typedChild && (child as FrameworkElement)?.Name == name)
{
return typedChild;
}
var result = FindVisualChild(child, name);
if (result != null)
return result;
}
return null;
}
ListViewItem GetListViewItem(int index)
{
if (ListDemo.ItemContainerGenerator.Status != GeneratorStatus.ContainersGenerated)
return null;
return ListDemo.ItemContainerGenerator.ContainerFromIndex(index) as ListViewItem;
}
private bool IsMouseOverTarget(Visual target, GetPositionDelegate getPosition)
{
Rect bounds = VisualTreeHelper.GetDescendantBounds(target);
Point mousePos = getPosition((IInputElement)target);
return bounds.Contains(mousePos);
}
private int GetCurrentIndex(GetPositionDelegate getPosition)
{
int index = -1;
for (int i = 0; i < ListDemo.Items.Count; ++i)
{
ListViewItem item = GetListViewItem(i);
if (item != null && this.IsMouseOverTarget(item, getPosition))
{
ListDemo recipeLevel = item.DataContext as ListDemo;
if (recipeLevel != null)
{
index = recipeLevel.Index;
break;
}
}
}
return index;
}
#endregion
写的比较粗糙,就是一个简单的底子(拓展性强),需要拓展的哥哥们可以自己加一下动画或者样式调整一下,有问题可以私信或者评论区,看到就会回