【问题标题】:Add item in ObservableCollection Ordered - C# UWP在 ObservableCollection 中添加项目 Ordered - C# UWP
【发布时间】:2016-04-21 08:08:10
【问题描述】:

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

问题:我有两个 ObservableCollections。 (OCAux - 辅助 OC,OCMain - 主 OC 绑定 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 的正确位置插入项目?

提前致谢

【问题讨论】:

  • 将其添加到 OCaux。然后订购它。使用 OCaux.indexOf(item) 获取添加项的索引。然后将其插入 OCMain。 OCMain.Insert(index,item);这是你想要的吗?
  • 我在 CollectionViewSource 中进行排序,但我只知道 WPF。另一个技巧是返回一个您排序的 IEnumerable 并在枚举上调用 NotifyProperty 更改,但这并非在所有情况下都有效。很确定并且 ObservableCollection 没有 InsertAt。

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


【解决方案1】:

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

1) 最简单的方法是添加一个BeginUpdate() 方法来禁用通知。完成收集工作后,您可以使用 EndUpdate() 重新启用通知。从ObservableCollection&lt;T&gt; 继承的类的概念证明:

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);
}

只需对CountItems 属性的INotifyPropertyChanged 接口引发事件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 通知更感兴趣,这应该不是问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-07-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-21
    • 1970-01-01
    • 2012-02-24
    • 2017-07-30
    相关资源
    最近更新 更多