Да, нормально вызывать Invoke
из потока, которому принадлежит дескриптор.
Подавляющее большинство примеров кода предлагает проверить InvokeRequired
, прежде чем решать, следует ли звонить Invoke
.
if (control.InvokeRequired)
{
control.Invoke(action);
}
else
{
action();
}
Однако это приводит к довольно загроможденному коду, и если вы должны поддерживать вызовы из потоков, не относящихся к GUI, тогда я рекомендую просто вызывать Invoke
напрямую во всех случаях. Есть небольшие накладные расходы по сравнению с вызовом InvokeRequired
, а затем и с самим delgate - см. Комментарии Ганса Пассанта к вопросу. Однако до тех пор, пока делегат выполняет значительную работу или этот код не находится в «горячей точке», накладные расходы должны иметь значение меньше, чем ясность кода.
Более того InvokeRequired
может дать ошибочные результаты, так как дескриптор элемента управления еще не выделен. Документация гласит:
Если дескриптор элемента управления еще не существует, InvokeRequired выполняет поиск
родительская цепочка элемента управления, пока он не найдет элемент управления или форму, которая делает
иметь ручку окна Если подходящей ручки найти не удается,
Метод InvokeRequired возвращает значение false.
Это означает, что InvokeRequired может вернуть false, если Invoke не
требуется (вызов происходит в том же потоке), или если элемент управления был
создан в другом потоке, но дескриптор элемента управления еще не
был создан.
В случае, когда дескриптор элемента управления еще не создан, вы
не должен просто вызывать свойства, методы или события в элементе управления.
Это может привести к тому, что дескриптор элемента управления будет создан на фоне
нить, изолирующая управление на нити без сообщения насоса и
делает приложение нестабильным.
Вы можете защитить от этого случая, также проверив значение
IsHandleCreated, когда InvokeRequired возвращает false на фоне
нить. Если дескриптор управления еще не создан, вы должны подождать
пока он не будет создан перед вызовом Invoke или BeginInvoke.
Как правило, это происходит только в том случае, если в
конструктор первичной формы для приложения (как в
Application.Run (новый MainForm ()), прежде чем форма будет показана или
Application.Run был вызван.
Так что я бы воспользовался советом из последнего приведенного выше абзаца и заменил рискованный InvokeRequired
код выше на:
control.Invoke(action);