我是WPF用户的长期用户,但对WinRT来说是新手。我想知道是否有内置方式或简单方法将交换功能集成到容器中,以便交换交换容器中的两个项目。所需的行为是拖动一个项目并将其放在另一个项目上,并将拖动的项目和拖动它的项目放在容器交换的位置。“
示例我有一个包含1 2 3 4 5 6 7 8的列表,如果我拖动 7 “on” 4 我希望交换这两个项目,以便结果列表变为1 2 3 7 5 6 4 8
我目前正在使用带有GridView
的{{1}}作为容器来显示大量图片缩略图。我需要能够重新排序它们,最常用的操作是交换两个图像的位置。
或者,如果没有内置方式,你能不能告诉我从头开始做的“正确”方向是WinRT?我正在考虑处理拖放而不是容器但是在项目级别,并手动交换ItemsWrapGrid
中的项目?
答案 0 :(得分:3)
现有的答案都会在数据级别为您进行交换。以下是可以使UI更加用户友好的方法。
恕我直言,处理交换的最佳用户体验是,当您拖动项目并将其移动到另一个项目时,后者应显示到拖动项目最初所在的位置。这清楚地告诉用户物品的确切位置。就像下面的gif图片上显示的一样。
要执行此操作,您需要创建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,因此您可以查看动画是如何完成的。请注意,数据交换部分不包括在内,正如我所说,其他答案已经很好地解释了。 :)
答案 1 :(得分:1)
最简单的方法是利用ObservableCollection
,让ListBox
或w / e控件来处理剩下的事情。
基本上,你所要做的就是制造阻力& drop handler,找出客户想要移动到哪个项目(跟踪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
中实现交换。
答案 2 :(得分:1)
以下是我的表现(感谢blog):
XAML代码:
<ListView x:Name="MyListView" CanDragItems="True" AllowDrop="True" HorizontalAlignment="Center" VerticalAlignment="Center" DragItemsStarting="MyListView_DragItemsStarting" Drop="MyListView_Drop">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" AllowDrop="True" Drop="TextBlock_Drop" DragOver="TextBlock_DragOver"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
C#代码:
ObservableCollection<string> MyList = new ObservableCollection<string>();
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<int> { MyList.IndexOf(DraggedString), MyList.IndexOf(DraggedOverTextBlock.Text) };
if (indexes[0] == indexes[1]) return;
indexes.Sort();
var values = new List<string> { 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;
}