В итоге я получил эту работу, используя комбинацию DragDropEvent.GetPosition, VisualTreeHelper.GetDescendantBounds и Rect.Contains. Вот что я придумал:
int index = -1;
for (int i = 0; i < collection.Count; i++)
{
var lbi = listBox.ItemContainerGenerator.ContainerFromIndex(i) as ListBoxItem;
if (lbi == null) continue;
if (IsMouseOverTarget(lbi, e.GetPosition((IInputElement)lbi)))
{
index = i;
break;
}
}
Код находится в событии ListBox Drop. Объект e - это объект DragEventArgs, переданный в событие Drop.
Реализация для IsMouseOverTarget:
private static bool IsMouseOverTarget(Visual target, Point point)
{
var bounds = VisualTreeHelper.GetDescendantBounds(target);
return bounds.Contains(point);
}