Как насчет Form.Invoke, когда уже в нужной теме? - PullRequest
2 голосов
/ 19 сентября 2011

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

Итак, мой вопрос: можно ли просто использовать Form.Invoke, хотя метод может быть вызван уже в нужном потоке? Или это создает накладные расходы или даже является возможным источником ошибки?

Ответы [ 2 ]

3 голосов
/ 19 сентября 2011

Да, нормально вызывать 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);
0 голосов
/ 19 сентября 2011

Вы можете проверить, нужно ли вам звонить Invoke.

if (myForm.InvokeRequired)
{
    // do invoke staff
} else
{
   // just execute your code without invoking 
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...