winRT拖放,交换两个项目而不是插入
我是WPF的长期用户,但对WinRT来说是新手。 我想知道是否有内置方式或简单的方法来集成容器中的交换function,以便交换交换容器中的两个项目。 所需的行为是拖动一个项目并将其放在另一个项目上,并将拖动的项目和拖动它的项目放在容器交换的位置。
示例我有一个列表1 2 3 4 5 6 7 8,如果我拖动7 “on” 4我希望交换两个项目,以便结果列表变为1 2 3 7 5 6 4 8
我目前正在使用带有ItemsWrapGrid
的GridView
作为它的容器来显示大量的图片缩略图。 我需要能够重新排序它们,最常用的操作是交换两个图像的位置。
或者,如果没有内置方式,你能不能告诉我从头开始做的“正确”方向是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; }