【问题标题】:UWP Reorder Gridviewitems on XboxUWP 在 Xbox 上重新排序 Gridview 项
【发布时间】:2018-07-15 21:39:40
【问题描述】:

我正在制作一个 UWP 应用程序,它现在应该在 xbox 上,将来可能会在 pc 和其他平台上发布。我知道在 PC 和移动设备上,我们可以通过 GridViewListView 上的以下 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 gridview,如果它可以与adaptivegridview一起使用的话。

Current Bheaviour 项被交换,但焦点保持在同一索引处。

预期焦点也应该随着项目移动。

【问题讨论】:

    标签: xaml gridview uwp xbox-one reorderlist


    【解决方案1】:

    您的发现是正确的,Xbox 开箱即用不支持拖放(尽管将来 Xbox 支持鼠标时,我想它会起作用)。

    因此,如果您需要此功能,则必须从一开始就手动实现它。一种选择是添加一个按钮,该按钮将仅显示在 Xbox 上,并且显示为 Reorder Grid

    启用此“重新排序”模式后,您可以使用多种解决方案。

    The easiest solution for you would be to set the SelectionMode to Single and when a item is selected, you would bring it to fromt of the underlying collection.

    collection.Remove( selectedItem );
    collection.Insert( 0, selectedItem );
    

    这个bring to front解决方案是在 Xbox One 仪表板上实现的,用于重新排序磁贴。

    第二个选项SelectionMode 设置为Multiple,用户将首先选择一个项目,然后选择第二个项目。之后,您可以将第一个选定的项目移动到第二个选定的项目之前:

    collection.Remove( firstSelectedItem );
    var targetIndex = collection.IndexOf( secondSelectedItem );
    collection.Insert( targetIndex, firstSelectedItem );
    

    最后的解决方案是最复杂的。使用SelectionMode = Single,您将选择一个项目,然后观察用户焦点移动的方向并“实时”移动磁贴。这是对用户最友好的,但最难可靠地实施。

    正如第三个解决方案的概述 - 如果您实现 GridView 的自定义模板,您可以捕获 GotFocus 事件:

    <GridView.ItemsPanel>
        <ItemsPanelTemplate>
            <ItemsWrapGrid Orientation="Horizontal" 
                           GotFocus="GridViewItem_GotFocus"/>
        </ItemsPanelTemplate>
    </GridView.ItemsPanel>
    

    现在在这个GotFocus 处理程序中,您可以从EventArgs.OriginalSource 检索当前具有焦点的项目。这样您就可以知道哪个项目获得了焦点,并且可以将其与用户选择的项目交换。

    更新 - hacky 解决方案

    我想出了一个解决 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));
        }
    }
    

    现在将集合项类型更改为这种新的“包装器”类型。当然,您还必须更新您的 GridView DataTemplate 以获得正确的参考。您现在需要使用"{Binding TvShow.Property}" 而不是"{Binding Property}",或者您可以将DataContext="{Binding TvShow}" 属性设置为DataTemplate 内的根元素。

    但是您现在可能会看到我的目标。目前您正在使用Move 方法来移动集合中的项目。让我们用交换替换它:

    var item1 = focusedItem.TvShow;
    focusedItem.TvShow = LostItem.TvShow;
    LostItem.TvShow = item1;
    

    这是一个很大的区别,因为我们不再更改集合本身,而只是将引用移动到包装在“静态”容器中的项目。并且由于绑定,项目将正确显示在它们应该显示的位置。

    这仍然是一个 hacky 解决方案,因为它要求您包装您的物品只是为了重新排序,但它至少可以工作。然而,我仍然有兴趣找到更好的方法来做到这一点。

    【讨论】:

    • 谢谢您的回答,我也在考虑做第三个选项之类的事情,我知道这可能很复杂,但我们该怎么做呢?有什么想法吗?
    • 我已经更新了我的答案,知道如何实现这个
    • 为什么要使用 GotFocus? I mean wont the got focus and selected element be the same?bcz when selection changes an item is selected and also gets the focus right?
    • 如果我只使用 grdivew 上的 selectionchanged 事件,然后将删除的项目与 args 中的选定项目交换怎么办?这行得通吗?
    • 或者我可以使用失去焦点和获得焦点,然后交换这两个元素?你有什么建议? @Martin Zikmund
    猜你喜欢
    • 1970-01-01
    • 2018-05-18
    • 2016-03-21
    • 2016-04-02
    • 2017-09-17
    • 1970-01-01
    • 2021-07-21
    • 2016-12-11
    相关资源
    最近更新 更多