У меня есть некоторый код, который я вынул из старого проекта, который вы можете использовать для достижения поведения перетаскивания. Он использует два списка, оба с включенным AllowDrop и некоторые события для обработки перетаскивания.
Данные испытаний:
var itemsInGroup1 = new ObservableCollection<MoveableItem>()
{
new MoveableItem {ID = 1, Name = "Item 1"},
new MoveableItem {ID = 2, Name = "Item 2"},
new MoveableItem {ID = 3, Name = "Item 3"},
};
var itemsInGroup2 = new ObservableCollection<MoveableItem>()
{
new MoveableItem {ID = 4, Name = "Item 4"},
new MoveableItem {ID = 5, Name = "Item 5"},
new MoveableItem {ID = 6, Name = "Item 6"},
};
List1.ItemsSource = itemsInGroup1;
List2.ItemsSource = itemsInGroup2;
ListBox:
<ListBox
x:Name="List2"
Grid.Column="2"
Margin="30"
AllowDrop="True"
BorderBrush="DarkBlue"
BorderThickness="2"
Drop="List_OnDrop"
PreviewMouseLeftButtonDown="List_OnPreviewMouseLeftButtonDown">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Name}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Вы захватываете DragSource, используя PreviewMouseLeftButtonDown
public ListBox DragSource { get; set; }
private void List_OnPreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
var listBox = (ListBox) sender;
if (listBox == null) return;
DragSource = listBox;
object data = GetDataFromListBox(DragSource, e.GetPosition(listBox));
if (data != null)
DragDrop.DoDragDrop(listBox, data, DragDropEffects.Move);
}
Данные получены из ListBox с помощью теста попадания в выбранном вами месте.
private static object GetDataFromListBox(ListBox source, Point point)
{
if (source.InputHitTest(point) is UIElement element)
{
object data = DependencyProperty.UnsetValue;
while (data == DependencyProperty.UnsetValue)
{
data = source.ItemContainerGenerator.ItemFromContainer(element);
element = VisualTreeHelper.GetParent(element) as UIElement;
if (element == source)
return null;
if (data != DependencyProperty.UnsetValue)
return data;
}
}
return null;
}
Наконец, в случае выпадения вы удаляете элемент из источника и помещаете его в цель.
private void List_OnDrop(object sender, DragEventArgs e)
{
var target = (ListBox) sender;
if (target.Name == DragSource.Name) return;
var data = e.Data.GetData(typeof(MoveableItem));
((IList) DragSource.ItemsSource).Remove(data);
((IList) target.ItemsSource).Add(data);
}
Я не рассмотрел вашу проблему обнаружения между объектами, поскольку кодовая база, из которой я извлек это, не требовала такой функциональности. Вы можете создать это в себе, подписавшись на DragOver на ItemTemplate, выяснить, между какими объектами в данный момент находится перетаскивание, и затем переупорядочить коллекцию после ее размещения.
Больше здесь:
https://docs.microsoft.com/en-us/dotnet/framework/wpf/advanced/drag-and-drop-overview
Редактировать: я нашел оригинальную статью - https://www.c -sharpcorner.com / uploadfile / dpatra / drag-and-drop-item-in-listbox-in-wpf /