我正在制作一个UWP应用程序,该应用程序现在应该在xbox上,也许将来可能会在PC和其他平台上发布它。我知道在PC和移动设备上,我们可以通过GridView
或ListView
上的以下2个属性启用此功能。
CanReorderItems=True
CanDrop=True
但根据Microsoft Docs,拖放功能为not available or supported on xbox。
那么在xbox GridView
上实现此重新排序功能的其他选项是什么?
更新1
所以这是gridview的后端代码。选择模式是单一的,但我没有使用selectionchanged事件,因为这只会产生很多混乱,现在只是假设我们总是需要交换项目,我将在交换完成后稍后设置布尔值。
private void SamplePickerGridView_ChoosingItemContainer(Windows.UI.Xaml.Controls.ListViewBase sender, ChoosingItemContainerEventArgs args)
{
if (args.ItemContainer != null)
{
return;
}
GridViewItem container = (GridViewItem)args.ItemContainer ?? new GridViewItem();
//should be xbox actually after pc testing
if (DeviceTypeHelper.GetDeviceFormFactorType() == DeviceFormFactorType.Desktop)
{
container.GotFocus += Container_GotFocus;
container.LostFocus += Container_LostFocus;
//container.KeyDown += Container_KeyDown;
}
args.ItemContainer = container;
}
private TVShow GotItem, LostItem;
private void Container_LostFocus(object sender, RoutedEventArgs e)
{
LostItem = OnNowAllGridView.ItemFromContainer(e.OriginalSource as GridViewItem) as TVShow;
GotItem = null;
}
private void Container_GotFocus(object sender, RoutedEventArgs e)
{
GotItem = OnNowAllGridView.ItemFromContainer(e.OriginalSource as GridViewItem) as TVShow;
if (GotItem != null && LostItem != null)
{
var focusedItem = GotItem;
var lostitem = LostItem;
var index1 = ViewModel.Source.IndexOf(focusedItem);
var index2 = ViewModel.Source.IndexOf(lostitem);
ViewModel.Source.Move(index1, index2);
}
LostItem = null;
}
你可以尝试使用adaptivegridview的代码,或者只是普通的uwp网格视图,如果它适用于它也应该与adaptivegridview一起工作。
当前Bheaviour 项目被转换但焦点保持在相同的索引。
预期焦点也应随项目一起移动。
答案 0 :(得分:1)
你的发现是真的,开箱即用的Xbox不支持拖放(虽然将来鼠标支持Xbox,我想它会起作用。)
因此,如果您需要此功能,则必须从头开始手动实施。一个选项是添加一个按钮,该按钮仅显示在Xbox上,读起来像Reorder Grid
。
当这个"重新排序"模式已启用,您可以使用多种解决方案。
最简单的解决方案就是将SelectionMode
设置为Single
,当选择某个项目时,您可以将其从基础集合中删除。< / p>
collection.Remove( selectedItem );
collection.Insert( 0, selectedItem );
这个带来前面的解决方案是在Xbox One仪表板上实现的,用于重新排序磁贴。
第二个选项是将SelectionMode
设置为Multiple
,其中用户首先选择一个项目,然后选择第二个项目。之后,您可以在选择的第二个项目之前移动第一个选定的项目:
collection.Remove( firstSelectedItem );
var targetIndex = collection.IndexOf( secondSelectedItem );
collection.Insert( targetIndex, firstSelectedItem );
最后一个解决方案是最复杂的。使用SelectionMode = Single
,您可以选择单个项目,然后观察用户焦点移动的方向并实时移动图块#34;。这是用户最友好的,但最难以可靠地实施。
正如第三个解决方案的大纲一样 - 如果您实施GotFocus
的自定义模板,则可以捕获GridView
事件:
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<ItemsWrapGrid Orientation="Horizontal"
GotFocus="GridViewItem_GotFocus"/>
</ItemsPanelTemplate>
</GridView.ItemsPanel>
现在,在此GotFocus
处理程序中,您可以从EventArgs.OriginalSource
检索当前焦点的项目。通过这种方式,您可以知道哪个项目获得了焦点,您可以将其与用户选择的项目进行交换。
我提出了一种解决GotFocus
/ LostFocus
混乱问题的hacky方法。
GotFocus
的问题在于,当我们在集合中移动项目时,焦点会变得混乱。但如果我们没有完全移动物品会怎样?
假设您的商品类型为TVShow
。让我们围绕这种类型创建一个包装器:
public class TVShowContainer : INotifyPropertyChanged
{
private TVShow _tvShow;
public TVShow TvShow
{
get => _tvShow;
set
{
_tvShow = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
现在将集合项类型更改为这个新的&#34;包装器&#34;类型。当然,您还必须更新GridView
DataTemplate
以获得正确的参考。您现在需要使用"{Binding Property}"
,而不是"{Binding TvShow.Property}"
,或者您可以将DataContext="{Binding TvShow}"
属性设置为DataTemplate
内的根元素。
但是你现在可以看到我要去哪里了。目前,您正在使用Move
方法移动集合中的项目。让我们用交换替换它:
var item1 = focusedItem.TvShow;
focusedItem.TvShow = LostItem.TvShow;
LostItem.TvShow = item1;
这是一个很大的区别,因为我们不再更改集合本身,而只是将引用移动到包含在&#34; static&#34;中的项目。容器。并且由于绑定,项目将正确地显示在他们应该的位置。
这仍然是一个hacky解决方案,因为它要求你只是为了重新排序包装你的项目,但它至少有效。然而,我仍然有兴趣找到更好的方法来做到这一点。