限制/缓冲一个基于Reactive Extensions中的另一个Observable集合

时间:2013-10-01 14:55:58

标签: c# system.reactive

我正在尝试生成生成的事件,我正在创建一个合并两种类型事件的流。我正在监视一组记录,如果

,事件可能会触发     1.添加/删除行时的CollectionChangedEvent。
    2.当项目的某个值发生变化时,PropertyChangedEvent

public IObservable<IEnumerable<ChangeDTO>> GetChangeStream()
{
     IObservable<IEnumerable<ChangeDTO>> allItems = 
     Observable.FromEventPattern<CollectionChangedEventArgs>(
                  x => source.CollectionChanged += x,
                  x => source.CollectionChanged-= x)
                  .Select(i => new ChangeDTO(source.SelectedItems, true, null)})
                  .Buffer(Timespan.FromMilliSeconds(300);                      

     IObservable<IEnumerable<ChangeDTO>> updatedItem = 
     Observable.FromEventPattern<PropertyChangedEventArgs>(
              x => source.PropertyChanged += x,
              x => source.PropertyChanged -= x).
              Select(i => new List<ChangeDTO>() {new ChangeDTO(new[] {source.Item}, false, source.UpdatedProperties)};

    return allItems.Merge(updatedItems);       
}

public class ChangeDTO
{
    ChangeDTO(IEnumerable<SourceDTO> items, bool recalculateAll, IEnumerable<string>   
     propertiesChanged)    
}

我试图清除PropertyChangedEvent缓冲区,如果CollectionChangedEvent在300毫秒内触发,即对属性更改不感兴趣并想要忽略它们。只有在没有触发CollectionChangedEvent的情况下,才会对属性更改感兴趣。

1 个答案:

答案 0 :(得分:2)

这有点牵扯,但我会试着简洁地解释一下!

核心思想是从缓冲的PropertyChangedEvents(PCE)流开始,但每次有CollectionChangedEvent(CCE)时都切换到新的缓冲流。最后,我们将CCE和扁平缓冲的PCE流合并在一起。

我们通过将CCE转换为Unit.DefaultStartWith的初始值来启动collectUpdateItems(这让我们可以在第一个CCE之前开始收集PCE)。然后将每个脉冲项目(Select)投射到新的缓冲PCE流中。 Switch将确保仅返回最新的缓冲区流。 Where只会删除空缓冲区。

最后我们Merge使用原始CCE流(投射到单个元素列表中以与PCE缓冲区兼容)。

希望这是有道理的!

稍微修改您的流以使用简单,无缓冲的ChangeDTO对象流开始:

IObservable<IEnumerable<ChangeDTO>> allItems = 
Observable.FromEventPattern<CollectionChangedEventArgs>(
    x => source.CollectionChanged += x,
    x => source.CollectionChanged-= x)
    .Select(i => new ChangeDTO(source.SelectedItems, true, null)});

IObservable<IEnumerable<ChangeDTO>> updatedItem = 
Observable.FromEventPattern<PropertyChangedEventArgs>(
    x => source.PropertyChanged += x,
    x => source.PropertyChanged -= x).
    .Select(i => new ChangeDTO(new[] {source.Item}, false, source.UpdatedProperties));

var collectUpdatedItems = allItems
    // We only need to know the CCE happened, not the details of it, so convert to Units
    .Select(_ => Unit.Default)
    // We must insert an event so PCEs are buffered before the first CCE
    .StartWith(Unit.Default)
    // Here we create a new PCE buffer stream at the start and after each CCE
    .Select(_ => updateItem.Buffer(TimeSpan.FromMilliseconds(300)))
    // On a CCE, switch to the new PCE buffer stream, dropping the current PCE buffer
    .Switch()
    // Finally drop any empty buffers
    .Where(i => i.Count > 0);

// merge the CollectionChangedEvents with the PropertyChangedEvent buffers
return collectionUpdateItems.Merge(allItems.Select(i => new List<ChangeDTO> {i}));