在可观察集合顺序 - C# UWP 中添加项



我有一个问题,这很无聊,我花了很多时间用最好的方式解决我的问题。

问题:我有两个可观察集合。(OCAux - Auxiliar OC, OCMain - Main OC Binded UI)

我有请求 http,5 个请求。 对于请求的每个响应,都会添加到项目中 OCAux,然后对项目进行排序。将其添加到订购到我的OCMain的每个项目中后,这会自动通知UI(绑定)。问题是,在添加新项目时,这不是订购的,因为我的订单是OCAux的结果,即仅根据请求请求订单。如果您在将项目添加到 OCMain 后订购项目,它确实会闪烁。我可以在每次添加项目时订购 OCMain,但在添加项目时会导致 UI 闪烁。

这被规避如下,但 UI 中仍然存在这些"闪烁":

                    foreach (var item in OCMain)
                    {
                        OCAux.Add(item);
                    }
                    ObservableCollection<Movies> moviesSortedByDatetime= new ObservableCollection<Movies>
                    (OCAux.OrderByDescending(item=> item.DateTime));
                    OCMain.Clear();
                    foreach (var item in moviesSortedByDatetime)
                    {
                        if (!OCMain.Contains(item))
                        { 
                          OCMain.Add(item);
                        }
                    }

有人知道如何将插入项放在可观察集合的正确位置吗?

提前致谢

对于批量插入,对于每个更改不断更新 UI 可能是(除非您需要实时更新)。除非您有充分的理由保留OCAux否则我会OCMain具有自定义IObservableCollection实现的有序集合,以在批处理完成后推迟通知。可以通过两种方式完成:

1)最简单的方法是添加一个禁用通知的BeginUpdate()方法。完成集合作业后,使用 EndUpdate() 重新启用通知。从ObservableCollection<T>继承的类的概念证明:

public void BeginUpdate() {
    _disableNotifications = true;
}
public void EndUpdate() {
    _disableNotifications = false;
    if (_changed) {
        OnCollectionChanged(
            new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
        _changed = false;
    }
}
protected override OnCollectionChanged(NotifyCollectionChangedEventArgs e) {
    if (_disableNotifications)
        _changed = true;
    else
        base.OnCollectionChanged(e);
}

只需将相同的逻辑也应用于INotifyPropertyChanged CountItems属性的接口引发事件PropertyChanged

2)第二个选项有点复杂,但即使您不知道批量操作何时开始和结束,它也可以工作。首先,让我们做一个假设:如果更新延迟 100 毫秒,用户不会注意到。在这种情况下,我们可以做的是忽略更改并在 NotificationDelay 毫秒后仅发送一个NotifyCollectionChangedAction.Reset。无论您有多少更新,只需在第一个更新的 NotificationDelay 毫秒后发送一个更新。概念验证:

protected override OnCollectionChanged(NotifyCollectionChangedEventArgs e) {
    // Another event already queued a delayed notification
    if (_isTimerRunning)
        return;
    // Assuming _timer is a System.Timers.Timer object already configured
    // and OnTimerElapsed method attached to its Elapsed event. Note that
    // you may also use System.Threading.Timer, pick the proper one
    // according to MSDN and your requirements
    _isTimerRunning = true;
    _timer.Start(); 
}
private void OnTimerElapsed(Object source, ElapsedEventArgs e) {
    _isTimerRunning = false;
    _timer.Stop();
    base.OnCollectionChanged(
        new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}

同样,您必须为INotifyPropertyChanged实现做类似的事情。

请注意,在这两种情况下,我们都会删除一些信息,因为CollectionChanged不会触发,例如,使用 NotifyCollectionChangedAction.Add 但仅使用 NotifyCollectionChangedAction.Reset 。无论如何,如果只是为了绑定,那么您对INotifyPropertyChanged通知更感兴趣,这应该不是问题。

最新更新