c# - winRT拖放,交换两个项目而不是插入

标签 c# windows-runtime winrt-xaml

我是 WPF 的长期用户,但对 WinRT 还很陌生。我想知道是否有一种内置方法或简单方法可以将交换功能集成到容器中,以便交换交换容器中的两个项目。所需的行为是拖动一个项目并将其放在另一个项目上,并交换被拖动的项目和被拖动到的项目在容器中的位置。

示例,如果我将 7 拖到“4”上,我有一个包含 1 2 3 4 5 6 7 8 的列表 我希望交换这两个项目,以便结果列表变为 1 2 3 7 5 6 4 8

我目前正在使用 GridViewItemsWrapGrid 作为显示大量图片缩略图的容器。我需要能够对它们重新排序,最常见的操作是交换两个图像的位置。

或者,如果没有内置方法,您能否提示我在 WinRT 中从头开始执行此操作的“正确”方向是什么?我正在考虑不在容器上而是在项目级别处理拖放,并手动交换 ObservableCollection 中的项目?

最佳答案

两个现有答案都将在数据级别为您进行交换。以下是可以使 UI 更加用户友好的方法。

恕我直言,处理交换的最佳用户体验是,当您拖动一个项目并将其移动到另一个项目上时,后者应该出现到拖动项目最初所在的位置。这清楚地告诉用户元素的确切去向。就像下面的 gif 图片所示。

drag, drop & swap

为此,您需要创建一个 Image 并使用 RenderTargetBitmap拖放项目的外观复制到其源,当拖动项目移动到放置项目上方。当然,当拖动操作开始时,您需要获取拖动项的位置,以便您知道该图像的确切放置位置。

然后,一旦元素被放下,您应该清除并隐藏图像并进行数据交换。

private void GridView_DragItemsStarting(object sender, DragItemsStartingEventArgs e)
{
    // get item container, i.e. GridViewItem
    var itemContainer = (GridViewItem)this.MyGridView.ContainerFromItem(e.Items[0]);

    // get drag item index from its item container
    _dragItemIndex = this.MyGridView.IndexFromContainer(itemContainer);

    // get drag item position
    var position = itemContainer.GetRelativePosition(this.LayoutRoot);

    // set the width and height of the image
    this.DropItemImage.Width = itemContainer.ActualWidth;
    this.DropItemImage.Height = itemContainer.ActualHeight;

    // move the image to this location
    this.DropItemImage.RenderTransformOrigin = new Point(0, 0);
    this.DropItemImage.RenderTransform.Animate(null, position.X, "TranslateX", 0, 0);
    this.DropItemImage.RenderTransform.Animate(null, position.Y, "TranslateY", 0, 0);
}

private void GridView_Drop(object sender, DragEventArgs e)
{
    // first we need to reset the image
    this.DropItemImage.Source = null;

    // get the drop & drop items
    var dragItem = _groups[_dragItemIndex];
    var dropItem = _groups[_dropItemIndex];

    // then we swap their positions
    _groups.RemoveAt(_dragItemIndex);
    _groups.Insert(_dragItemIndex, dropItem);
    _groups.RemoveAt(_dropItemIndex);
    _groups.Insert(_dropItemIndex, dragItem);
}

private object _previous;
private async void ItemRoot_DragOver(object sender, DragEventArgs e)
{
    // first we get the DataContext from the drop item in order to retrieve its container
    var vm = ((Grid)sender).DataContext;

    // get the item container
    var itemContainer = (GridViewItem)this.MyGridView.ContainerFromItem(vm);

    // this is just to stop the following code to be called multiple times druing a DragOver
    if (_previous != null && _previous == itemContainer)
    {
        return;
    }
    _previous = itemContainer;

    // get drop item index from its item container
    _dropItemIndex = this.MyGridView.IndexFromContainer(itemContainer);

    // copy the look of the drop item to an image
    var bitmap = new RenderTargetBitmap();
    await bitmap.RenderAsync(itemContainer);
    this.DropItemImage.Source = bitmap;

    // animate the image to make its appearing more interesting
    this.DropItemImage.Animate(0, 0.4, "Opacity", 200, 0);
    this.DropItemImage.RenderTransformOrigin = new Point(0.5, 0.5);
    this.DropItemImage.RenderTransform.Animate(0.8, 1, "ScaleX", 200, 0, new ExponentialEase { EasingMode = EasingMode.EaseIn });
    this.DropItemImage.RenderTransform.Animate(0.8, 1, "ScaleY", 200, 0, new ExponentialEase { EasingMode = EasingMode.EaseIn });
}

我包含了一个小示例项目 here这样您就可以查看动画是如何完成的。请注意,正如我所说,数据交换部分不包括在内,其他答案已经很好地解释了。 :)

关于c# - winRT拖放,交换两个项目而不是插入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27741599/

相关文章:

c# - 指定 WPF 图表的最小和最大轴

c# - 为什么 WinRT MediaElement.SetSource 不执行它应该执行的操作?

audio - 是否有用于在Windows RT中播放自定义视频和音频格式的库/工具?

error-handling - ABI 是否保留比 HRESULT 更多的错误信息?

xaml - 如何将控件高度数据绑定(bind)到另一个控件的高度?

c# - Windows Phone 8.1 数据绑定(bind) ListView [XAML]

xaml - 用于在将鼠标悬停在不同控件上时切换控件可见性的 Windows 8 XAML 解决方案

c# - 无法让 SignalR Hub 变量停止丢失值(静态变量不是问题)

c# - 如何从 SqlDataReader 返回单个值?

c# - 用其他XAML文件中的网格替换内容WPF网格控件