UWP / C#:ObservableCollection就地排序(没有滚动)

时间:2017-06-01 09:01:14

标签: c# sorting uwp observablecollection

在UWP应用中,我正在尝试对绑定到ObservableCollection的{​​{1}}进行排序 - 因此ListView(创建新集合)不是一种选择。

到目前为止,我使用了这种扩展方法:

collection.OrderBy(..)

不幸的是,这种方式导致当前的'滚动偏移'由于public static void Sort<TSource, TKey>(this ObservableCollection<TSource> source, Func<TSource, TKey> keySelector) { List<TSource> sortedList = source.OrderBy(keySelector).ToList(); source.Clear(); foreach (var sortedItem in sortedList) { source.Add(sortedItem); } } 而被重置,并且相应的source.Clear()滚动一直回到顶部 - 这是非常糟糕的用户体验。

有什么想法吗?

2 个答案:

答案 0 :(得分:4)

您可以尝试创建一个 temp 集合,其中包含原始集合中的所有项目,对其进行排序,然后循环遍历其项目,并仅重新排序需要的位置。得到更新。像这样的东西 -

public static void Sort<TSource, TKey>(this ObservableCollection<TSource> source, Func<TSource, TKey> keySelector)
{
    var sortedSource = source.OrderBy(keySelector).ToList();

    for (var i = 0; i < sortedSource.Count; i++)
    {
        var itemToSort = sortedSource[i];

        // If the item is already at the right position, leave it and continue.
        if (source.IndexOf(itemToSort) == i)
        {
            continue;
        }

        source.Remove(itemToSort);
        source.Insert(i, itemToSort);
    }
}

此外,您希望ListView在项目动画时保持滚动偏移。这可以通过设置 -

来完成
<ItemsPanelTemplate>
    <ItemsStackPanel ItemsUpdatingScrollMode="KeepScrollOffset" />
</ItemsPanelTemplate>

我发现这个与UX相关的问题非常有趣,我甚至最终为它创建了一个demo project。 :)下面的 gif 演示了最终结果。对我而言,它提供了一种更好的体验,因为我在视觉上知道,哪些项目是通过排序重新定位的。

ListView sorting animation

答案 1 :(得分:1)

前一段时间我正在处理同样的问题而且我最终得到了这个问题:

Func<TempoMarking, IComparable> selectorGetter = null;
// Setting the selectorGetter here
for (int i = 0; i < Collection.Count; i++)
{
    for (int j = 0; j < Collection.Count - 1; j++)
    {
        YourType currentItem = Collection[j];

        if (selectorGetter(currentItem).CompareTo(selectorGetter(Collection[j + 1])) == 1)
        {
            Collection.Remove(currentItem);
            Collection.Insert(j + 1, currentItem);
        }
    }
}

它可能不是最好的解决方案,它在L640这样的手机上有点落后但是它有效。如果您需要滚动到ListView中的某个项目,可以使用以下方法:

YourListView.ScrollIntoView(ListViewItemToScrollTo);