Обновить ObservableCollection с помощью BlockingCollection

Я подписываюсь на сервис, который будет вызывать событие при получении нового элемента, я добавляю этот элемент в BlockingCollection,
У меня работает второй поток, который будет зацикливать BlockingCollection добавить / обновить элемент в наблюдаемой коллекции.

Проблема в том, как вы добавляете в ObservableCollection? Я знаю, я не могу просто сделать .add на этот тип коллекции, как это должно быть сделано в потоке пользовательского интерфейса. Поэтому я попытался использовать разные ObservableCollection подкласс, который использует диспетчер, чтобы маршалировать добавление элемента, но каждый раз, я получаю ту же ошибку

"Произошло необработанное исключение типа" System.StackruException "в неизвестном модуле".

с советами по устранению неполадок, как:

убедитесь, что у вас нет бесконечного цикла или бесконечной рекурсии.

Ну, дело в том, что у меня есть какой-то бесконечный цикл на самом деле, как BlockingQueue постоянно получает новые элементы, например, от 5 до 10 в секунду.
Я не получу исключения, если не буду связывать контроль с observablecollection хотя, или если я использую список вместо.

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 третьей стороны.

2 ответа

Решение

Это прекрасный пример того, где Reactive Extensions - очень полезный и оригинальный инструмент. Существует довольно крутая кривая обучения их использованию, но, поскольку у вас есть конкретный пример, я вставлю реактивный код, который достигнет вашей цели, при условии, что я правильно понимаю вашу цель.

Обратите внимание, что вам нужно будет установить Reactive Extensions, и вам понадобятся два оператора using (System.Reactive.Linq и System.Reactive.Subjects), и вам нужно будет ссылаться на dll System.Reactive и System.Reactive.Windows.Threading. См. Реактивный на 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);
        }
    }
}

В ответе есть небольшая ошибка. Смотрите исправленную строку ниже:

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

Мне потребовалось некоторое время, чтобы понять это, но ответ rmayer06 решил мою проблему. Я не могу комментировать ответы, или я бы получил.

Другие вопросы по тегам