Xaml GridView:在Drop事件上获取索引

Xaml GridView:在Drop事件上获取索引,xaml,gridview,windows-runtime,windows-store-apps,winrt-xaml,Xaml,Gridview,Windows Runtime,Windows Store Apps,Winrt Xaml,在GridView的OnDrop事件中放置GridView项目时,如何获取索引或位置?正如我所读到的,GridView.ItemContainerGenerator.ContainerFromItem(item)可以使用,但对我来说,ItemContainerGenerator是null 这是我当前的代码: void gridMain_DragItemsStarting(object sender, DragItemsStartingEventArgs e) { var item = e

GridView
OnDrop
事件中放置
GridView项目时,如何获取索引或位置?正如我所读到的,
GridView.ItemContainerGenerator.ContainerFromItem(item)
可以使用,但对我来说,
ItemContainerGenerator
null

这是我当前的代码:

void gridMain_DragItemsStarting(object sender, DragItemsStartingEventArgs e)
{
    var item = e.Items.First();
    var source = sender;
    e.Data.Properties.Add("item", item);
    e.Data.Properties.Add("source", sender);
}

void gridMain_Drop(object sender, DragEventArgs e)
{
    var item = e.Data.Properties.Where(p => p.Key == "item").Single();

    object source;
    e.Data.Properties.TryGetValue("source", out source);
    var s = ((GridView)source).ItemContainerGenerator.ContainerFromItem(item);
}

任何提示或建议都会非常有用。

使用DragEventArgs的GetPosition方法查找项目被删除的位置,然后计算实际索引,有关处理程序,请参阅下面的代码片段。以此作为答案提出了类似的问题(场景3)

private void GridView\u Drop(对象发送方,DragEventArgs e)
{
GridView视图=发送方作为GridView;
//获取您的数据
var item=e.Data.Properties.Where(p=>p.Key==“item”).Single();
//在gridview中查找项目将被放置的位置
点位置=e.GetPosition(view.ItemsPanelRoot);
//获取其中一个列表项的大小
GridViewItem gvi=(GridViewItem)视图.ContainerFromIndex(0);
双项目高度=gvi.ActualHeight+gvi.Margin.Top+gvi.Margin.Bottom;
//从项目位置确定项目的索引(假设所有项目大小相同)
int index=Math.Min(view.Items.Count-1,(int)(位置Y/itemHeight));
//使用索引和数据调用viewmodel。
}

<强>编辑:>,请将其视为一个原型。我试过了,它工作正常,但您可以根据您的场景修改它(调整延迟超时,立即区分更多TaskCompletionSource,等等)

其思想是在删除操作之后启动一项任务,以检查该项是否仅被删除或重新排序

private async void observateCollection\u CollectionChanged(对象发送方,System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
if(e.Action==System.Collections.Specialized.NotifyCollectionChangedAction.Remove)
{
对象removedItem=e.OldItems[0];
var reorderTask=NoticeReorderAsync(removedItem);
尝试
{
var task=wait task.whenay(reorderstask,task.Delay(100));
if(reorderTask==任务)
{
//removedItem实际上已重新排序
Debug.WriteLine(“重新排序”);
}
其他的
{
TryCancelReorder();
//removedItem确实被删除了
Debug.WriteLine(“removedItem”);
}
}
捕获(TaskCanceledException ex)
{
WriteLine(“removedItem(来自异常)”;
}
最后
{
tcs=null;
}
}
else if(e.Action==System.Collections.Specialized.NotifyCollectionChangedAction.Add)
{
对象addedItem=e.NewItems[0];
bool added=noticead(addedItem);
如有(新增)
{
//addedItem刚刚添加,没有重新排序
Debug.WriteLine(“添加”);
}
}
}
taskcompletionsourcetcs;
私有void TryCancelReorder()
{
如果(tcs!=null)
{
tcs.trysetconceled();
tcs=null;
}
}
私有任务通知OrderAsync(对象已删除)
{
TryCancelReorder();
tcs=新任务完成源(已删除);
返回tcs.Task;
}
私人bool NoticeAdd(添加对象)
{
如果(tcs!=null)
{
尝试
{
if(object.Equals(tcs.Task.AsyncState,已添加))
{
tcs.TrySetResult(新增);
返回false;
}
其他的
{
tcs.trysetconceled();
返回true;
}
}
最后
{
tcs=null;
}
}
返回true;
}

谢谢您的评论。但是,无论我将拖动的元素
放置在何处,索引
始终是
0
?现在看到您的两个事件处理程序都以
gridMain
开头,您试图实现什么?如果您只想通过拖动对项目进行重新排序,只需将
GridView
绑定到
ObservableCollection
并将其属性
CanReorderItems
AllowDrop
设置为
True
。是的,这将使我的生活更轻松。但是在
CollectionChanged
事件中,我无法区分重新排序和添加/删除。所以我必须手动处理所有事件。你能更具体地说明区分它们的原因吗?由于重新排序引发2个后续事件(删除和添加),因此可以添加一些专用字段来跟踪删除的项目。如果add事件包含已删除的相同项,则知道列表已重新排序(然后清除该私有字段)。但是,如果您想知道该项目是否刚刚被删除,那么它有点麻烦。请参阅此答案的编辑。非常相关: