Description
Describe the problem
When dragging and dropping from one ListView to another you sometimes need to know the index of the dropped item so you can update a model accordingly. DragEventArgs
doesn't expose this information, so it has to be manually calculated by the position of the drop and the current scroll container state.
Describe the solution
Provide an extension method (a convenience wrapper over this Stack Overflow solution) that allows you to calculate the drop index by simply calling myListView.GetDropIndex(e)
:
public static class ListViewExtensions
{
public static int GetDropIndex(this ListView listView, DragEventArgs e)
{
var scrollViewer = VisualTreeHelper.GetChild(VisualTreeHelper.GetChild(listView, 0), 0) as ScrollViewer;
var position = e.GetPosition(listView);
var positionY = scrollViewer.VerticalOffset + position.Y;
return GetItemIndex(positionY, listView);
}
private static int GetItemIndex(double positionY, ListView targetListView)
{
var index = 0;
double height = 0;
foreach (var item in targetListView.Items)
{
height += GetRowHeight(item, targetListView);
if (height > positionY)
{
return index;
}
index++;
}
return index;
}
private static double GetRowHeight(object listItem, ListView targetListView)
{
var listItemContainer = targetListView.ContainerFromItem(listItem) as ListViewItem;
var height = listItemContainer.ActualHeight;
var marginTop = listItemContainer.Margin.Top;
return marginTop + height;
}
}
Example usage:
private void MyListOnDrop(object sender, DragEventArgs e)
{
if (!(sender is ListView listView))
{
return;
}
var insertIndex = listView.GetDropIndex(e);
// ...
}
Alternatives
I've previously derived a new DragDropListView
that wrapped all this logic up and exposed a DroppedAtIndex
property as well, but the extension method is much cleaner because it allows you to work with an out-of-the-box ListView
.
Additional info
No response
Help us help you
Yes, but only if others can assist.