Почему невозможно обновить ObservableCollection из другого потока?

В многопоточном приложении WPF невозможно обновить ObservableCollection из потока, отличного от потока окна WPF.

Я знаю , что есть обходные пути , поэтому мой вопрос не в том, как избежать «. Этот тип CollectionView не поддерживает изменения в его SourceCollection из потока, отличного от потока Dispatcher . «Исключение.

У меня вопрос: , почему существует такое исключение? Почему нельзя было разрешить обновления коллекций из какого-либо потока?

Лично я не вижу причин для блокировка обновления пользовательского интерфейса при изменении ObservableCollection из других потоков. Если два потока (в том числе параллельные) обращаются к одному и тому же объекту, один прослушивает изменения свойств объекта через события, другой выполняет изменения, он всегда будет работать, по крайней мере, при правильном использовании блокировок. Итак, каковы причины?

8
задан Arseni Mourzenko 5 June 2010 в 14:04
поделиться

2 ответа

Во-первых ... Я чувствую твою боль. Ограничение потока пользовательского интерфейса может быть проблемой ...

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

У меня вопрос, почему существует такой исключение?

Ну, вкратце, история. Windows существует некоторое время, и то, как некоторые части работы Gui встроены в такие технологии, как COM и тому подобное ... так что изменить это нетривиально ... очень легко что-то сломать. Я уверен, что есть много других проблем ... но кто-то умнее меня должен их объяснить. Я считаю, что команда WPF действительно хотела снять это ограничение, и они очень усердно работали над этим ... в конце концов, я думаю, что количество необходимых изменений в основной ОС было невыполнимым ... поэтому они двинулись дальше ... крысы.

Почему нельзя было разрешить сбор обновлений из любого потока?

Это было и возможно ... Создание чего-то поточно-ориентированного всегда требует некоторых затрат производительности и добавляет сложности. В большинстве случаев приложение не требует многопоточного доступа.Важно понимать, что по большей части Microsoft действует по тем же правилам, что и мы, и с теми же ограничениями. Если бы они сделали ObservableCollection потокобезопасным ... они бы использовали те же инструменты, что и у нас ... блокировки, мониторы и т.д. те же правила.

Я знаю, что есть обходные пути, поэтому мой вопрос не в том, как избежать этого тип CollectionView не поддержать изменения в SourceCollection из потока отличается от потока Диспетчера " исключение.

Обходных путей нет ... Обойти нечего. ObservableCollection не работает ... он просто не ориентирован на многопоточность. Вы должны сделать его или доступ к нему поточно-ориентированным. То же самое для всего, что не является потокобезопасным ... если вам нужно, чтобы это было потокобезопасным, сделайте это так. Если вы используете потоки, то вы знаете о блокировках и тому подобном ... используйте их ... вот для чего они нужны.

... блокировать обновление пользовательского интерфейса, когда ObservableCollection изменен с другие потоки .... он всегда будет работать, по крайней мере, если используются замки правильно ....

Если замки используются правильно ... Именно! Опять же, Microsoft могла установить эти блокировки, но они этого не сделали, и по очень веским причинам. Вы можете установить блокировки. Или вы можете использовать другую тактику, которая даст вам поточно-безопасный доступ ... множество вариантов.

Библиотека параллельных задач в .net4.0 предоставляет некоторые новые инструменты для решения этих проблем. Возможность установить контекст для задачи или потока особенно полезна ...

  // get the Ui thread context
  _uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();

  Action DoInBackground = new Action(() =>
  {
    /*...In the background...
      ...process some data for an ObservableCollection...*/
  });

  Action DoOnUiThread = new Action(() =>
  { 
    /*...On the UI thread...
      ...read/write data to an ObservableCollection...*/
  });

  // start the background task
  var t1 = Task.Factory.StartNew(() => DoInBackground());
  // when t1 is done run t1..on the Ui thread.
  var t2 = t1.ContinueWith(t => DoOnUiThread(), _uiScheduler);

Не думайте о требованиях сходства потоков в элементах пользовательского интерфейса как о чем-то, что можно обойти ....это просто способ, которым он работает.

В C # и .Net есть много инструментов, которые позволяют сделать многопоточность менее кошмаром. Используйте их ... они могут быть забавными.

Я иду покурить.

16
ответ дан 5 December 2019 в 06:22
поделиться

Если ваша коллекция привязана к элементам пользовательского интерфейса, эти элементы пользовательского интерфейса слушают CollectionChanged событие коллекции, и это событие поднимается в потоке, на котором вы обновляете коллекцию.

Таким образом, проблема заключается в элементах пользовательского интерфейса, доступ к которым возможен только из потока, в котором они были созданы, а не в самой коллекции.

10
ответ дан 5 December 2019 в 06:22
поделиться
Другие вопросы по тегам:

Похожие вопросы: