我有一个实时有很多更新的列表,所以我想在每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);
}
这似乎很不错!!
答案 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);