Avalonia 列表拖拽替换

  • Avalonia 列表拖拽替换已关闭评论
  • 170 次浏览
  • A+
所属分类:.NET技术
摘要

实现目标,在一个ListBox中选择一个子项进行拖拽到另一个ListBox中,拖拽到某一子项区域进行替换

实现目标,在一个ListBox中选择一个子项进行拖拽到另一个ListBox中,拖拽到某一子项区域进行替换

axaml代码

Avalonia 列表拖拽替换Avalonia 列表拖拽替换

 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

Avalonia 列表拖拽替换Avalonia 列表拖拽替换

<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

给源ListBox添加指针移动事件

Avalonia 列表拖拽替换Avalonia 列表拖拽替换

 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指针移动

 将目标ListBox设为允许拖入

DragDrop.SetAllowDrop(platePositionListBox, true); 

由于ListBox没有DropEvent事件,需要进行添加事件

 platePositionListBox.AddHandler(DragDrop.DropEvent, PlatePositionListBox_DropEvent, RoutingStrategies.Bubble | RoutingStrategies.Direct); 

对应事件实现,其中需要获取到需要替换的项的下标,本处是通过定位进行计算

Avalonia 列表拖拽替换Avalonia 列表拖拽替换

 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     }

具体实现

最终效果:

初始画面

Avalonia 列表拖拽替换

拖拽后:

Avalonia 列表拖拽替换