5

我订阅了一项服务,该服务将在收到新元素时引发事件,我将此元素添加到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);
            }
        }
    }

编辑当我追踪它时,该错误自行消失了。我试图让事情变得更简单,以便真正了解问题所在,然后它开始起作用。当把东西重新组合在一起时,它仍然可以工作......但它会不时地回来,因为似乎不相关的原因,比如在我的列表视图中添加样式。我开始认为第三方 dll 存在问题。

4

2 回答 2

3

这是反应式扩展是一个非常有用和巧妙的工具的一个完美例子。使用它们有一个非常陡峭的学习曲线,但是由于您在这里有一个特定的案例,因此假设我正确理解您的目标,我将插入将实现您的目标的反应式代码。

请注意,您需要安装 Reactive Extensions,并且需要两个 using 语句(System.Reactive.Linq 和 System.Reactive.Subjects),并且需要引用 System.Reactive 和 System.Reactive.Windows.Threading dll。请参阅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);
        }
    }
}
于 2012-11-05T15:08:12.707 回答
0

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

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

我花了一段时间才弄清楚这一点,但 rmayer06 的回答解决了我的问题。我不能对答案发表评论,否则我会的。

于 2013-02-24T20:44:14.000 回答