问题
This article shows how to implement a copy operation on a drop event. I'd like to do the same but I want my dropped item to appear in the collection according to where it was placed on the UI. So I need the StartIndex much like on a NotifyCollectionChangedEventArgs when an ObservableCollection changes. In the article you'll see that eventually you get a SelectionCollection object whose items have an Index property. But unfortunately this is the index of the source collection (where it was picked) and not the destination collection (where it was dropped).
回答1:
Ok, this is quite ugly, but I didn't find another way, not by myself and also not by searching the net for answers. Must have been another deadline at Microsoft that prevented the rather obvious functionality to be included...
Basically the method below does everything manually, getting the drop location and checking it for listbox items to use as index references.
private void ListBoxDragDropTarget_Drop(object sender, Microsoft.Windows.DragEventArgs e)
{
// only valid for copying
if (e.Effects.HasFlag(DragDropEffects.Copy))
{
SelectionCollection selections = ((ItemDragEventArgs)e.Data.GetData("System.Windows.Controls.ItemDragEventArgs")).Data as SelectionCollection;
int? index = null;
if (selections != null)
{
Point p1 = e.GetPosition(this.LayoutRoot); // get drop position relative to layout root
var elements = VisualTreeHelper.FindElementsInHostCoordinates(p1, this.LayoutRoot); // get ui elements at drop location
foreach (var dataItem in this.lbxConfiguration.Items) // iteration over data items
{
// get listbox item from data item
ListBoxItem lbxItem = this.lbxConfiguration.ItemContainerGenerator.ContainerFromItem(dataItem) as ListBoxItem;
// find listbox item that contains drop location
if (elements.Contains(lbxItem))
{
Point p2 = e.GetPosition(lbxItem); // get drop position relative to listbox item
index = this.lbxConfiguration.Items.IndexOf(dataItem); // new item will be inserted immediately before listbox item
if (p2.Y > lbxItem.ActualHeight / 2)
index += 1; // new item will be inserted after listbox item (drop location was in bottom half of listbox item)
break;
}
}
if (index != null)
{
foreach (var selection in selections)
{
// adding a new item to the listbox - adjust this to your model
(lbxConfiguration.ItemsSource as IList<ViewItem>).Insert((int)index, (selection.Item as ViewItem).Clone());
}
}
}
}
}
来源:https://stackoverflow.com/questions/3790986/get-drop-index-in-silverlight-drag-drop