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

我是WPF的长期用户,但对WinRT来说是新手。 我想知道是否有内置方式或简单的方法来集成容器中的交换function,以便交换交换容器中的两个项目。 所需的行为是拖动一个项目并将其放在另一个项目上,并将拖动的项目和拖动它的项目放在容器交换的位置。

示例我有一个列表1 2 3 4 5 6 7 8,如果我拖动7 “on” 4我希望交换两个项目,以便结果列表变为1 2 3 7 5 6 4 8

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

或者,如果没有内置方式,你能不能告诉我从头开始做的“正确”方向是WinRT? 我正在考虑不在容器处理拖放而是在项目级别,并手动交换ObservableCollection的项目?

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

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

拖放,交换

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

然后,一旦项目被删除,您应该清除并隐藏图像并进行数据交换。

 private void GridView_DragItemsStarting(object sender, DragItemsStartingEventArgs e) { // get item container, ie 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 }); } 

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

最简单的方法是利用ObservableCollection ,让ListBox或w / e控件来处理其余的事情。

基本上,你所要做的就是创建拖放处理程序,找出客户想要移动到哪个项目(跟踪oldIndex / newIndex),并实现交换:

 var dragSourceItem = yourObservable[oldIndex]; var dragTargetItem = yourObservable[newIndex]; yourObservable[newIndex]=dragSourceItem; yourObservable[oldIndex]=dragTargetItem; 

ObservableCollection将引发’替换’动作,WPF知道如何处理。

这里有一些东西可以帮助您: http : //www.hardcodet.net/2009/03/moving-data-grid-rows-using-drag-and-drop

您基本上希望将其包装到附加行为中,并在ViewModel实现交换。

我是这样做的(感谢这个博客 ):

XAML代码:

         

C#代码:

 ObservableCollection MyList = new ObservableCollection(); string DraggedString; TextBlock DraggedOverTextBlock; protected override void OnNavigatedTo(NavigationEventArgs e) { MyList.Add("1"); MyList.Add("2"); MyList.Add("3"); MyList.Add("4"); MyList.Add("5"); MyList.Add("6"); MyList.Add("7"); MyList.Add("8"); MyList.Add("9"); MyList.Add("10"); MyListView.ItemsSource = MyList; } private void MyListView_DragItemsStarting(object sender, DragItemsStartingEventArgs e) { DraggedString = e.Items[0] as String; } private void MyListView_Drop(object sender, DragEventArgs e) { if (DraggedString == null || DraggedOverTextBlock == null) return; var indexes = new List { MyList.IndexOf(DraggedString), MyList.IndexOf(DraggedOverTextBlock.Text) }; if (indexes[0] == indexes[1]) return; indexes.Sort(); var values = new List { MyList[indexes[0]], MyList[indexes[1]] }; MyList.RemoveAt(indexes[1]); MyList.RemoveAt(indexes[0]); MyList.Insert(indexes[0], values[1]); MyList.Insert(indexes[1], values[0]); DraggedString = null; DraggedOverTextBlock = null; } private void TextBlock_DragOver(object sender, DragEventArgs e) { DraggedOverTextBlock = sender as TextBlock; }