2010-11-08 2 views
1

Хорошо известно, что вы не можете обновлять пользовательский интерфейс из любого другого потока, кроме потока пользовательского интерфейса.Non-UI thread, UI access

Однако, я только что обнаружил некоторый код, который получает значение virtualviewize listview из потока без UI без исключения.

Так что, на самом деле, мой вопрос: Какое взаимодействие у вас есть с пользовательским интерфейсом из не-интерфейса?

Спасибо Тео

+1

Исправьте меня, если я ошибаюсь, но чтение значения из другого потока ничего не обновляет, так что это возможно. Если вам нужно *** изменить *** что-то в пользовательском интерфейсе, вам нужно синхронизировать действие с потоком пользовательского интерфейса, используя диспетчер пользовательского интерфейса, например, если он доступен. –

+2

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

ответ

5

Потому что он работает без выбрасывания исключения, не означает, что вы должны сделать это.

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

+0

Не работает ли пользовательский интерфейс, что он использует? –

+1

Нет. В частности, потому, что в документации явно отмечается, что эти объекты не поддерживают многопоточность (см. Главу классов Thread Safety ), они не прилагают никаких усилий для блокировки этих вещей. –

+0

Ответ дан, как вы ответили первым! –

3

Особое правило состоит в том, что вы не можете вызвать функцию Windows API, которая использует ручку окна. Не совсем очевидно, будет или нет использовать свойство или вызвать метод элемента управления, что вызовет такой вызов API. В документах MSDN перечислены только 4 из них, которые всегда безопасны для использования: InvokeRequired, Invoke(), BeginInvoke() и CreateGraphics().

Но да, иногда значение свойства доступно и не требует вызова API. Хорошим примером является свойство Text. Он кэшируется, потому что он используется так часто. Чтение Свойство Text не генерирует исключение, вы просто получаете кешированное значение. Но пишет Свойство текста переходит в kaboom, для обновления текста на экране требуется вызов API. ListView.VirtualSize работает точно так же.

Вы не получите исключение, но оно все еще не кошерное. В конце концов, поток пользовательского интерфейса может также изменить свойство Text, а позже - через микросекунду. Вы получите устаревшее значение, классическую проблему с потоками, известную как состояние гонки.

+0

Так что, по существу, вы можете уйти от него, но, не надо! –

+1

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