将列表(ObservableCollection)复制到另一个列表

时间:2014-07-30 13:11:47

标签: c# list system.reactive

我有一个实时有很多更新的列表,所以我想在每1秒后将此Observable Collection中的所有更改复制到另一个。我该怎么做?

我尝试的是:

var temp = CalculateMyObservableCollection();
var temp2 = (INotifyCollectionChanged) temp.SourceCollection;

Observable.FromEventPattern<CollectionChangeEventArgs>(temp2, "CollectionChanged")
                .Throttle(new TimeSpan(1000))
                .Select(i => i.Sender)
                .Subscribe(UpdateItems);

private void UpdateItems(object obj)
{
    if (obj is MyClass)
        Items.AddNewItem(obj as MyClass);
}

这似乎很不错!!

2 个答案:

答案 0 :(得分:1)

我已经实现了一个可能解决您问题的受限制的可观察集合。

INotifyCollectionChanged接口可以提供详细的更改通知,描述确切的集合更改,其中更改操作由事件args的Action属性指示。但是,当更改受到限制时,您无法跟踪有关更改的详细信息,因为无法表示添加和删除元素的复杂更改。相反,必须使用Reset操作来表示集合的内容发生了显着变化

class ThrottledObservableCollection<T> : IReadOnlyCollection<T>, INotifyCollectionChanged, INotifyPropertyChanged, IDisposable {

  List<T> _list;

  IDisposable _subscription;

  public ThrottledObservableCollection(ObservableCollection<T> source, TimeSpan throttleInterval) {
    if (source == null)
      throw new ArgumentNullException("source");
    _list = new List<T>(source);
    _subscription = Observable
      .FromEventPattern<NotifyCollectionChangedEventHandler, NotifyCollectionChangedEventArgs>(
        handler => source.CollectionChanged += handler,
        handler => source.CollectionChanged -= handler
      )
      .Throttle(throttleInterval)
      .Subscribe(HandleSourceChanged);
  }

  void HandleSourceChanged(EventPattern<NotifyCollectionChangedEventArgs> eventPattern) {
    var source = (IEnumerable<T>) eventPattern.Sender;
    _list = new List<T>(source);
    OnPropertyChanged("Count");
    OnCollectionChanged();
  }

  public Int32 Count { get { return _list.Count; } }

  public IEnumerator<T> GetEnumerator() {
    return _list.GetEnumerator();
  }

  IEnumerator IEnumerable.GetEnumerator() {
    return GetEnumerator();
  }

  public event PropertyChangedEventHandler PropertyChanged;

  protected void OnPropertyChanged(String propertyName) {
    var handler = PropertyChanged;
    if (handler != null)
      handler(this, new PropertyChangedEventArgs(propertyName));
  }

  public event NotifyCollectionChangedEventHandler CollectionChanged;

  protected void OnCollectionChanged() {
    var handler = CollectionChanged;
    if (handler != null)
      handler(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
  }

  public void Dispose() {
    Dispose(true);
  }

  protected void Dispose(Boolean disposing) {
    _subscription.Dispose();
  }

}

请注意,此类不是线程安全的,如果多个线程同时更改源集合,则可能需要一些额外的保护。

以下是如何使用该集合:

var observableCollection = new ObservableCollection<Item>();
var throttledObservableCollection = new ThrottledObservableCollection<Item>(
  observableCollection,
  TimeSpan.FromSeconds(1)
);
throttledObservableCollection.CollectionChanged += ...

// 2 CollectionChanged events will fire from this code.
observableCollection.Add(new Item());
observableCollection.Add(new Item());
Thread.Sleep(TimeSpan.FromSeconds(1.1));
observableCollection.Add(new Item());

答案 1 :(得分:0)

与评论一样,最好更详细地说明为什么需要这样做。

看起来你想要的只是改变了可观察集合的对象的身份('发送者'),在这种情况下,列表中的重复是什么?

但是如果你不能为什么不使用Buffer运算符:

   Observable.FromEventPattern<CollectionChangeEventArgs>(temp2, "CollectionChanged")
             .Buffer(new TimeSpan(1000))
             .Where(x => x.Any())
             .Select(x => i.Sender)
             .Subscribe(UpdateItems);