更新绑定集合时 ListView 闪烁

ListView flickering when updating binding collection

我正在开发 Windows 10 通用应用程序,当我在我的应用程序中使用 ListView 时发现一些闪烁问题。我的 ListView 使用 x:Bind 绑定到我的视图模型中的 ObservableCollection。

当用户执行某些操作或发生后台更新时,我会执行一些需要刷新 ObservableCollection 的处理。

    private ObservableCollection<Item> UIItems = new ObservableCollection<Item>();
    private bool IsUpdating = false;

    private void UpdateUIProperties(List<Item> newItems)
    {
        DispatcherHelper.CheckBeginInvokeOnUI(() =>
        {
            IsUpdating = true;
            UIItems.Clear();
            foreach (var item in newItems)
            {
                if (item.IsVisible)
                {
                    UIItems.Add(item);
                }
            }
            IsUpdating = false;
        });
    }

这段代码执行完后,ListView开始闪烁,然后Scrollviewer一直到最上面。有什么方法可以防止这种情况发生并使 ListView 的 ScrollViewer 保持在其原始偏移量?

一个似乎对我有用的解决方案是将 Itemsource 绑定到一个 Observable 集合,然后让另一个集合包含您要添加的项目。让集合中的项目实现下面的接口。当您想要更新集合时,请使用 MergeCollection 方法来确保集合中的项目得到保留,但它们具有新的配置。

    public interface IConfigureFrom<T>
    {
        void ConfigureFrom(T other);
    }

    public static void MergeCollection<T>(ICollection<T> source, ICollection<T> dest)  where T : IConfigureFrom<T>, new()
    {
        // First remove entries at the bottom of the dest list that are no longer there
        if (dest.Count > source.Count)
        {
            for (int i = dest.Count - 1; i >= source.Count; i--)
            {
                var coll = dest as Collection<T>;
                if (coll != null)
                {
                    coll.RemoveAt(i);
                }
                else
                {
                    dest.Remove(dest.Last());
                }
            }
        }

        // reconfigure existing entries with the new configureation
        var sourecList = source.ToList();
        var destList = dest.ToList();

        for (int i = dest.Count - 1; i >= 0; i--)
        {
            var target = destList[i];
            var config = sourecList[i];
            target.ConfigureFrom(config);
        }


        // add new entries at the end and configure them from the source list
        for (int i = dest.Count; i < source.Count; i++)
        {
            T newItem = new T();
            newItem.ConfigureFrom(sourecList[i]);
            dest.Add(newItem);
        }

    }

更改 ListView 中的所有项目时,通常最好只交换整个 ItemsSource。

刚刚设置:

UIItems = new List<...>(your data); 

当然,让它触发 OnNotifyPropertyChanged。