使用BlockingCollection更新ObservableCollection

时间:2012-11-05 14:27:08

标签: c# wpf observablecollection blockingcollection

我订阅了一个服务,当收到一个新元素时会引发一个事件,我将这个元素添加到BlockingCollection
我有第二个运行的线程将循环BlockingCollection以添加/更新可观察集合中的元素。

问题是如何添加ObservableCollection? 我知道我不能在这种类型的集合上做.add,因为它需要在UI线程上完成。所以我尝试使用不同的ObservableCollection子类来使用调度程序来编组元素的添加,但每次都会出现相同的错误

  

“类型'System.StackOverflowException'的未处理异常   发生在未知模块中。“

提供以下问题排查提示:

  

确保没有无限循环或无限偏移。

嗯,实际上,我确实有某种无限循环,因为BlockingQueue一直在接收新元素,例如每秒5到10个。 如果我没有将控件绑定到observablecollection,或者我使用的是List,那么我不会得到异常。

Class ElementHolder
{
    private ExternalService _externalService;
    private ObservableCollection<Element> _elementsList = new ObservableCollection<Element>();
    private BlockingCollection<Element> _elementsReceived = new BlockingCollection<Element>();

    public ObservableCollection<Element> ElementsList
    {
        get
        {
            return _elementList;
        }
        set
        {
            _elementList = value;
        }
    }

public ElementHolder()
    {
        Task.Factory.StartNew(ReadElements);
        _externalService = new ExternalService();
        _externalService.ReceivedNewElement += new Action<Element>(o => _elementsReceived.Add(o));
        _externalService.Subscribe();
    }

private void ReadElements()
    {
        foreach (Element element in _elementsReceived.GetConsumingEnumerable())
        {
            Element item = _elementsList.FirstOrDefault(o => o.ID == element.ID);
            if (item == null)
            {
                _elementList.Add(element);
            }
            else
            {
                item.Update(element);
            }
        }
    }

EDIT 当我跟踪它时,这个bug本身消失了。我试图让事情变得更简单,以便真正了解问题所在,然后开始起作用。把东西放回去的时候它仍然可以工作......但它时不时地回来,因为似乎无关的原因就像在我的列表视图中添加一个样式。我开始认为第三方dll存在问题。

2 个答案:

答案 0 :(得分:3)

这是Reactive Extensions是一个非常有用和巧妙的工具的完美示例。使用它们有一个相当陡峭的学习曲线,但由于你在这里有一个特定的案例,我将插入能实现你的目标的反应性代码,假设我正确理解你的目标。

请注意,您需要安装Reactive Extensions,并且需要两个using语句(System.Reactive.Linq和System.Reactive.Subjects),您需要引用System.Reactive和System.Reactive.Windows。穿线dll。请参阅Reactive on MSDN

class ElementHolder
{
    public ObservableCollection<Element> ElementsList { get; set; }
    private ExternalService _externalService = new ExternalService();
    private IDisposable _elementSubscription;
    private Subject<Element> _elementSubject = new Subject<Element>();

    public ElementHolder()
    {
        _externalService.ReceivedNewElement += _elementSubject.OnNext;
        _externalService.Subscribe();

        ElementList = new ObservableCollection<Element>();
        _elementSubscription = _externalService.ObserveOnDispatcher().Subscribe(NextElement);
    }

    private void NextElement(Element e)
    {
        Element item = ElementsList.FirstOrDefault(o => o.ID == element.ID);
        if (item == null) {
            _elementList.Add(element);
        }
        else {
            item.Update(element);
        }
    }
}

答案 1 :(得分:0)

答案中有一个小错误。请参阅下面的更正行:

_elementSubscription = _elementSubject.ObserveOnDispatcher().Subscribe(NextElement);

我花了一段时间来解决这个问题,但是rmayer06的答案解决了我的问题。我不能评论答案,或者我会说。