在ObservableCollection中添加项目Ordered - C#UWP

时间:2016-04-21 08:08:10

标签: c# wpf win-universal-app observablecollection

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

问题:我有两个ObservableCollections。 (OCAux - Auxiliar OC,OCMain - 主要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);
                        }
                    }

任何人都知道如何将项目插入ObservableCollection的正确位置?

提前致谢

1 个答案:

答案 0 :(得分:0)

对于批量插入,可以为每次更改不断更新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);
}

INotifyPropertyChangedPropertyChanged属性的Count界面提升事件Items也应用相同的逻辑。

2)第二个选项稍微复杂一点,但即使您不知道批量操作何时开始和结束,它仍然有效。首先,让我们做一个假设:用户不会注意到更新是否会延迟100毫秒。在这种情况下,我们可以做的是忽略更改,并在NotifyCollectionChangedAction.Reset毫秒后发送一个NotificationDelay。拥有多少更新并不重要,只有一个会在第一个更新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通知更感兴趣,这应该不是问题。