Код ниже взят из доказательства разработчика, над которым я сейчас работаю:
using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
...
QueueProcessor = new Task(() =>
{
while (processorrunning)
{
if (processorrunning && dq.Count != 0)
{
boxid = string.Empty;
if (dq.TryDequeue(out boxid))
{
if (textBox1.InvokeRequired)
{
textBox1.Invoke(new MethodInvoker(() =>
{
if (textBox1.Text == string.Empty)
textBox1.Text = boxid;
else
textBox1.Text += Environment.NewLine + boxid;
textBox1.Refresh();
}));
}
else
{
if (textBox1.Text == string.Empty)
textBox1.Text = boxid;
else
textBox1.Text += Environment.NewLine + boxid;
textBox1.Refresh();
}
}
else
{
throw new Exception("Exception removing boxid from queue.");
}
}
else
{
trigger.WaitOne(600000, false);
}
}
});
Все условия if возвращают значение true. Имеется допустимая строка boxid, назначенная boxid из вызова dq.TryDequeue. Все, кроме кода вызова, работает как надо. Код никогда не использует else в тесте InvokeRequired.
Form1.textBox1 никогда ничего не видит. Идеи приветствуются.
@ZohirSalak: Пробовал это по вашему предложению, и это не имело значения.
Ваша задача вообще начата?
Код никогда не войдет в ветку else
, потому что (насколько я понимаю) цикл выполняется в фоновом потоке. Следовательно, Control.InvokeRequired
, вызываемый в этом потоке, всегда будет true
.
@Zohir: Да. Я проходил через это несколько раз.
Этот textBox1.Text = boxid;
назначает пустую строку, поэтому этот if (textBox1.Text == string.Empty)
всегда будет истинным, поэтому else никогда не попадет
@Zohir: (dq.TryDequeue (out boxid)) заполняет boxid допустимым значением.
Поскольку у меня нет полного кода, я удалил эту строку и назначил строку сразу, когда происходит (dq.TryDequeue(out boxid))
и заполняется textboxBox, я также закомментировал эту строку trigger.WaitOne(600000, false);
Это была ошибка дизайна в .NET 1.0, они дали наименее верному методу кратчайшее имя. Control.Invoke () очень проблематичен из-за высокой вероятности возникновения тупиковой ситуации, проблемы, от которой BeginInvoke () не страдает. Вы должны использовать его только тогда, когда вам нужно его возвращаемое значение, которое само по себе неверно в 98% случаев из-за высокой вероятности создания ошибки гонки потоков. В противном случае отладить легко, используйте окно отладчика Debug> Windows> Threads. Показывает, что делает основной поток. Обычно что-то неразумное, например, ожидание завершения потока.
@Hans: Спасибо! Я буду иметь это в виду. Можно было подумать, что они уже обновили документы ...;)
Это задокументировано, но это ничего не значит для тех, кто еще не обнаружил необходимость в окне отладчика Debug> Windows> Threads для диагностики тупиковой ситуации. Распределение потоков сложно реализовать правильно, используйте его экономно и категорически избегайте изобретения собственного кода, когда классы BackgroundWorker и Task и ключевые слова await / async могут сделать эту работу за вас.
Вы пробовали использовать
Invoke()
, а неtextBox1.Invoke()
?