【问题标题】:UWP/C#: ObservableCollection sort in-place (w/o scrolling)UWP/C#:ObservableCollection 就地排序(无滚动)
【发布时间】:2017-11-02 08:01:48
【问题描述】:

在 UWP 应用中,我尝试对绑定到 ListViewObservableCollection 进行排序 - 因此,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() 和相应的ListView 一直滚动到顶部,当前的“滚动偏移”被重置 - 这是非常糟糕的用户体验。

有什么想法吗?

【问题讨论】:

  • 我不熟悉您的要求,请问您是否尝试在 source.Clear() 之前将“滚动偏移”保存在对象中并再次重置该值,这可能会有所帮助。
  • 那将是我的“最后手段”。它可能会起作用,但使用 source.Clear() 列表将首先滚动到顶部,然后在重置为存储的“滚动偏移量”后不久。这看起来很奇怪。

标签: c# sorting uwp observablecollection


【解决方案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);

【讨论】:

    【解决方案2】:

    您可以尝试创建一个 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>
    

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

    【讨论】:

    • 你可以调用 observables 暴露的 .Move 而不是 source.Remove 和 Insert。它在内部做同样的事情。要记住的一件事是调用 Move 将触发集合更改事件,这可能会或可能不会受到欢迎。
    猜你喜欢
    • 2016-04-27
    • 1970-01-01
    • 2020-02-11
    • 2013-05-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-02
    • 2017-09-04
    相关资源
    最近更新 更多