Avalonia 列表拖拽替换
实现目标,在一个ListBox中选择一个子项进行拖拽到另一个ListBox中,拖拽到某一子项区域进行替换
axaml代码
1 <ListBox
2 Name="consumableListBox"
3 Margin="5"
4 ItemsSource="{Binding ConsumableList}"
5 SelectionMode="Single">
6 <ListBox.ItemTemplate>
7 <DataTemplate>
8 <StackPanel Margin="5,5,5,0">
9 <Border
10 Width="160"
11 Height="100"
12 Margin="0,0,0,5"
13 HorizontalAlignment="Center"
14 Background="Red"
15 CornerRadius="5" />
16 <TextBlock HorizontalAlignment="Center" Text="{Binding}" />
17 </StackPanel>
18 </DataTemplate>
19 </ListBox.ItemTemplate>
20 </ListBox>
<ListBox
Name="platePositionListBox"
Margin="5"
ItemsSource="{Binding PlatePositionList}"
SelectionMode="Single">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Margin="5,5,5,0">
<Border
Width="160"
Height="100"
Margin="0,0,0,5"
HorizontalAlignment="Center"
Background="Red"
CornerRadius="5" />
<TextBlock HorizontalAlignment="Center" Text="{Binding}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
给源ListBox添加指针移动事件
1 private void SourceList_PointerMoved(object sender, PointerEventArgs e)
2 {
3 // 当拖拽操作开始时,在源列表中开始拖拽
4 if (e.GetCurrentPoint(consumableListBox).Properties.IsLeftButtonPressed)
5 {
6 DataObject dataObject = new DataObject();
7 dataObject.Set("dataObject", consumableListBox.SelectedItem);
8 DragDrop.DoDragDrop(e, dataObject, DragDropEffects.Move);
9 }
10 }
将目标ListBox设为允许拖入
DragDrop.SetAllowDrop(platePositionListBox, true);
由于ListBox没有DropEvent事件,需要进行添加事件
platePositionListBox.AddHandler(DragDrop.DropEvent, PlatePositionListBox_DropEvent, RoutingStrategies.Bubble | RoutingStrategies.Direct);
对应事件实现,其中需要获取到需要替换的项的下标,本处是通过定位进行计算
1 private void PlatePositionListBox_DropEvent(object? sender, DragEventArgs e)
2 {
3 var a = e.Data.Get("dataObject");
4 if (e.Data.Contains("dataObject") && a != null)
5 {
6 var targetIndex = GetDropTargetIndex(platePositionListBox, e.GetPosition(platePositionListBox));
7 if (targetIndex >= 0)
8 {
9 if (this.DataContext is PlanViewModel viewModel)
10 {
11 viewModel.PlatePositionList.RemoveAt(targetIndex);
12 viewModel.PlatePositionList.Insert(targetIndex, a.ToString());
13 }
14 }
15 }
16 }
17
18
19 //获取目标项下标
20 private int GetDropTargetIndex(ListBox targetListBox, Avalonia.Point position)
21 {
22 var itemsControl = targetListBox;
23
24 var itemsPoint = GetAllItemDistances(targetListBox);
25 var firstItemPanel = (StackPanel)Avalonia.VisualTree.VisualExtensions.FindDescendantOfType<StackPanel>(itemsControl);
26 var itemContainer = (Control)firstItemPanel;
27 var firstItemBounds = itemContainer.Bounds;
28 var items = itemsControl.Items;
29 var y = firstItemBounds.Y;
30 for (int i = 0; i < items.Count; i++)
31 {
32 if (itemsPoint[i].Index == -1)
33 {
34 continue;
35 }
36 if (position.Y >= itemsPoint[i].DistanceToTop && position.Y <= itemsPoint[i].DistanceToTop + firstItemBounds.Height)
37 {
38 return i;
39 }
40 }
41 return items.Count;
42 }
43
44 //获取目标ListBox的项距离顶部边框的距离,如果未呈现到画面上,下标设为-1
45 private List<ItemCoordinates> GetAllItemDistances(ListBox listBox)
46 {
47 var itemCoordinatesList = new List<ItemCoordinates>();
48 var items = listBox.Items;
49 var scrollViewer = listBox.FindDescendantOfType<ScrollViewer>();
50 var topOffset = scrollViewer.Offset.Y;
51
52 for (int i = 0; i < items.Count; i++)
53 {
54 var itemContainer = listBox.ItemContainerGenerator.ContainerFromIndex(i) as Control;
55 if (itemContainer != null)
56 {
57 var itemBounds = itemContainer.Bounds;
58 var distanceToTop = itemBounds.Top - topOffset;
59 itemCoordinatesList.Add(new ItemCoordinates(i, distanceToTop));
60 }
61 else
62 {
63 itemCoordinatesList.Add(new ItemCoordinates(-1, -999));
64 }
65 }
66 return itemCoordinatesList;
67 }
对应的实体类
1 public class ItemCoordinates
2 {
3 public int Index { get; }
4 public double DistanceToTop { get; }
5
6 public ItemCoordinates(int index, double distanceToTop)
7 {
8 Index = index;
9 DistanceToTop = distanceToTop;
10 }
11 }
最终效果:
初始画面
拖拽后:
本文来自博客园,作者:逸羽澜心,转载请注明原文链接:https://www.cnblogs.com/fengxinyuan/p/17604442.html