【问题标题】:GridView: Get Index on Drop EventGridView:获取拖放事件的索引
【发布时间】:2014-12-02 12:00:23
【问题描述】:

如何在GridViewOnDrop 事件中获取GridViewItemindexposition?正如我所读到的那样,GridView.ItemContainerGenerator.ContainerFromItem(item) 是可能的,但对我来说ItemContainerGeneratornull

这是我当前的代码:

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);
}

任何提示或建议都会很有帮助。

【问题讨论】:

标签: xaml gridview windows-runtime windows-store-apps winrt-xaml


【解决方案1】:

使用 DragEventArgs 的 GetPosition 方法找到项目被放置的位置,然后计算实际的索引,请参见下面的代码 sn-p 处理程序。 here 使用此 MSDN example 作为答案提出了类似的问题(场景 3)。

private void GridView_Drop(object sender, DragEventArgs e)
{
    GridView view = sender as GridView;

    // Get your data
    var item = e.Data.Properties.Where(p => p.Key == "item").Single();

    //Find the position where item will be dropped in the gridview
    Point pos = e.GetPosition(view.ItemsPanelRoot);

    //Get the size of one of the list items
    GridViewItem gvi = (GridViewItem)view.ContainerFromIndex(0);
    double itemHeight = gvi.ActualHeight + gvi.Margin.Top + gvi.Margin.Bottom;

    //Determine the index of the item from the item position (assumed all items are the same size)
    int index = Math.Min(view.Items.Count - 1, (int)(pos.Y / itemHeight));

    // Call your viewmodel with the index and your data.
}

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

这个想法是在 Remove 操作后启动一个任务,以检查该项目是仅被删除还是重新排序。

private async void observableCollection_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
    if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Remove)
    {
        object removedItem = e.OldItems[0];
        var reorderTask = NoticeReorderAsync(removedItem);
        try
        {
            var task = await Task.WhenAny(reorderTask, Task.Delay(100));

            if (reorderTask == task)
            {
                // removedItem was in fact reordered
                Debug.WriteLine("reordered");
            }
            else
            {
                TryCancelReorder();
                // removedItem was really removed
                Debug.WriteLine("removedItem");
            }
        }
        catch (TaskCanceledException ex)
        {
            Debug.WriteLine("removedItem (from exception)");
        }
        finally
        {
            tcs = null;
        }
    }
    else if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add)
    {
        object addedItem = e.NewItems[0];
        bool added = NoticeAdd(addedItem);
        if (added)
        {
            // addedItem was just added, not reordered
            Debug.WriteLine("added");
        }
    }

}

TaskCompletionSource<object> tcs;

private void TryCancelReorder()
{
    if (tcs != null)
    {
        tcs.TrySetCanceled();
        tcs = null;
    }
}

private Task NoticeReorderAsync(object removed)
{
    TryCancelReorder();
    tcs = new TaskCompletionSource<object>(removed);

    return tcs.Task;
}

private bool NoticeAdd(object added)
{
    if (tcs != null)
    {
        try
        {
            if (object.Equals(tcs.Task.AsyncState, added))
            {
                tcs.TrySetResult(added);
                return false;
            }
            else
            {
                tcs.TrySetCanceled();
                return true;
            }
        }
        finally
        {
            tcs = null;
        }
    }
    return true;
}

【讨论】:

  • 感谢您的评论。但无论我将拖动的元素放在哪里,index 始终是0 ??
  • 现在看到你的两个事件处理程序都以gridMain 开头,你想达到什么目的?如果您只想通过拖动重新排序项目,只需将GridView 绑定到ObservableCollection 并将其属性CanReorderItemsAllowDrop 设置为True 即可。
  • 是的,这会让我的生活更轻松。但在CollectionChanged 事件中,我无法区分重新排序和添加/删除。所以我必须手动处理所有事件。
  • 您能否更具体地说明区分它们的原因?由于重新排序会触发 2 个后续事件(删除和添加),因此您可以添加一些私有字段来跟踪已删除的项目。如果添加事件包含已删除的相同项目,则您知道列表已重新排序(然后您清除该私有字段)。但是,如果您想知道该项目是否刚刚被删除,那么它就有点麻烦了。请参阅此答案的编辑。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-04
  • 2012-11-03
  • 2016-02-27
相关资源
最近更新 更多