Control.Invoke() зависает

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

Внутри этого фонового рабочего мне нужно получить доступ к графическому интерфейсу и изменить/прочитать его, поэтому мне нужен control.Invoke(). «Иногда» Invoke застревает на самом вызове вызова и не выполняет делегат. Мой основной поток работает нормально и не блокируется. Я все еще могу взаимодействовать с графическим интерфейсом, делая другие вещи. Прежде чем публиковать какой-либо код: существуют ли какие-либо другие условия для выполнения control.Invoke(), кроме

  • Основной поток графического интерфейса не блокируется
  • Контроллер должен существовать, дескриптор создан и не может быть удален.

Основной поток не обязательно должен быть свободным и именно вызов называется правильно? Он должен продолжаться, когда основной поток простаивает...

Спасибо за любую помощь

Обновление:

Вот ситуация с потоком во время этой проблемы: введите здесь описание изображенияОсновной поток выполняет это:

Application.Run(appContext);

Так что бездействует. Рабочий поток ожидает в этой строке:

fileName = (string)cbPrintFile.Invoke(new Func<String>(() => cbPrintFile.Text));

который не выполняется, как я указал выше. cbPrintFile — поле со списком


person DerApe    schedule 11.03.2013    source источник
comment
Вы должны использовать обработчик событий ReportProgress и т. д., чтобы сообщить потоку пользовательского интерфейса. См. stackoverflow.com/questions/3289920/.   -  person MoonKnight    schedule 11.03.2013
comment
Вы говорите, что открываете форму, а затем запускаете своего фонового работника по методу OnFormClosing. Какие элементы управления вы затем обновляете с помощью control.Invoke()? Если вы пытаетесь обновить форму, которая пытается закрыться, это может быть частью вашей проблемы...   -  person Dan Puzey    schedule 11.03.2013
comment
+1 только за сходство названия с «Control.Invoke() отстой».   -  person Martin James    schedule 11.03.2013
comment
@DanPuzey нет, потому что без фонового рабочего это работает   -  person DerApe    schedule 11.03.2013
comment
@Killercam Я не хочу сообщать о каком-либо прогрессе в пользовательском интерфейсе, а просто читаю и устанавливаю некоторые поля графического интерфейса.   -  person DerApe    schedule 11.03.2013
comment
@derape: Итак, какой элемент управления вы вызываете control.Invoke? Если вы запускаете код во время OnFormClosing, то разница в поведении при использовании BackgroundWorker может быть огромной. Это может помочь, если вы разместите код...!   -  person Dan Puzey    schedule 11.03.2013
comment
@DanPuzey Я обновил свой пост. Это поле со списком. Не уверен, какой код вам, ребята, понадобится, чтобы помочь мне здесь   -  person DerApe    schedule 11.03.2013
comment
Можете ли вы опубликовать весь метод OnFormClosing?   -  person Dan Puzey    schedule 11.03.2013
comment
@DanPuzey Метод FormClosing просто запускает фоновую работу, вот и все. Метод, который запускается рабочим, довольно большой... есть ли что-то особенное, что вы ищете?   -  person DerApe    schedule 11.03.2013


Ответы (1)


Invoke означает "поставить в очередь и дождаться обработки". Если он «зависает», это говорит о том, что вы зашли в тупик, например, потому, что поток пользовательского интерфейса все еще находится в обработчике событий, ожидающем рабочего. Если код правильно разделен, вы, вероятно, можете заменить Invoke на BeginInvoke, что позволит рабочему процессу продолжить работу после постановки в очередь. Конечно, также было бы хорошо убедиться, что пользовательский интерфейс никогда не ждет работника. Это можно сделать случайно, если попытаться удерживать lock (на одном и том же объекте) в обоих местах. Вы можете провести расследование, просто приостановив работу приложения, нажав ctrl+d,t, чтобы открыть темы, и ctrl+d,c, чтобы просмотреть стек вызовов каждого из них по очереди.

person Marc Gravell    schedule 11.03.2013
comment
Если код правильно разделен, вы, вероятно, можете заменить Invoke на BeginInvoke, как здесь помогает разделение, пожалуйста, развейте мои сомнения. - person TalentTuner; 11.03.2013
comment
Я обновил свой пост, чтобы показать актуальную ситуацию. Я согласен, что если бы основной поток был занят, это заблокировало бы его, но это не так. BeginInvoke не решит эту проблему, верно? Потому что он просто останется там и никогда не будет выполняться так, как сейчас. Кроме того, если мне нужно значение, прочитанное из графического интерфейса, оно не будет возвращено. - person DerApe; 11.03.2013