【问题标题】:ListView flickering when updating binding collection更新绑定集合时 ListView 闪烁
【发布时间】:2015-06-25 18:32:33
【问题描述】:

我正在开发一个 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 保持原来的偏移量?

【问题讨论】:

    标签: xaml listview win-universal-app


    【解决方案1】:

    似乎对我有用的解决方案是将 Itemsource 绑定到 Observable 集合,然后拥有另一个包含您要添加的项目的集合。让集合中的 Item 实现下面的接口。当您想要更新集合时,请使用 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);
            }
    
        }
    

    【讨论】:

      【解决方案2】:

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

      刚刚设置:

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

      当然要让它触发 OnNotifyPropertyChanged。

      【讨论】:

      • 这样做的问题是它会导致 ListView 在 UIItems 集合更新后滚动到顶部。使用上述解决方案,滚动偏移量将保持不变。
      • 将 ItemsUpdatingScrollMode 设置为 KeepScrollOffset:参见此处:stackoverflow.com/questions/27924000/…
      • 但老实说:无论如何删除集合中的所有项目时,视图真的应该保留吗?如果您只是更改一些项,为什么不只更新这些而不是重新填充集合?
      猜你喜欢
      • 2015-03-18
      • 2015-02-25
      • 2020-03-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-02-29
      • 1970-01-01
      相关资源
      最近更新 更多