Каждый раз, когда новичок спрашивает что-то вроде: Как обновить графический интерфейс из другого потока на C #? , ответ довольно прост:
if (foo.InvokeRequired)
{
foo.BeginInvoke(...)
} else {
...
}
Но действительно ли это хорошо использовать ? Сразу после того, как поток без графического интерфейса выполнит foo.InvokeRequired
, состояние foo
может измениться. Например, если мы закроем форму сразу после foo.InvokeRequired
, но до foo.BeginInvoke
, вызов foo.BeginInvoke
приведет к InvalidOperationException
]: Invoke или BeginInvoke нельзя вызвать для элемента управления, пока не будет создан дескриптор окна. Этого не произойдет, если мы закроем форму перед вызовом InvokeRequired
, потому что это будет false
даже при вызове из потока без графического интерфейса.
Другой пример. Допустим, foo
- это TextBox
. Если вы закроете форму и после этого поток без графического интерфейса выполнит foo.InvokeRequired
(что неверно, потому что форма закрыта) и foo.AppendText
, это приведет к ObjectDisposedException
.
Напротив, на мой взгляд, использование WindowsFormsSynchronizationContext
намного проще - отправка обратного вызова с использованием Post
будет происходить, только если поток все еще существует, а синхронные вызовы с использованием Отправить
бросает InvalidAsynchronousStateException
, если поток больше не существует.
Разве не проще использовать WindowsFormsSynchronizationContext
? Я что-то пропустил? Почему мне следует использовать шаблон InvokeRequired-BeginInvoke, если он? не совсем потокобезопасный? Как вы думаете, что лучше?