Я унаследовал некоторый код с двумя потоками, отличными от UI, которые обновляют различные элементы управления WinForm.
Код использует InvokeRequired и Invoke для обновления пользовательского интерфейса; однако я все еще время от времени получаю сообщение об ошибке: Неверная операция кросс-потоков: Control 'lvReports' доступ к потоку, отличному от того, на котором он был создан.Winform: несколько потоков, обновляющих пользовательский интерфейс в одно и то же время
Я подозреваю, что имею дело с состоянием гонки, и что мне нужно ввести замок в нижеприведенный метод, но я сказал, что я могу найти десятки примеров того, как обновлять пользовательский интерфейс из не-интерфейса, безопасно, но нет примеры или обсуждение того, как бороться с двумя потоками, обновляющими одни и те же элементы управления в сценарии гонки.
Итак, мой вопрос: как мне переписать код ниже, чтобы обрабатывать пользовательский интерфейс, правильно заданный условие гонки, и что мне нужно обновить интерфейс от потоков, отличных от UI?
// two separate theads call this method in a instance of a WinForm
private void LoadReports()
{
if (this.InvokeRequired)
{
this.Invoke(new MethodInvoker(this.LoadReports));
}
else
{
// some code removed to keep exampe simple...
SetCtlVisible(lvReports, true);
if (this.InvokeRequired)
{
this.Invoke((MethodInvoker)delegate { lvReports.Refresh(); });
}
else
{
lvReports.Refresh();
}
}
}
delegate void SetVisibleCallback(Control ctl, bool visible);
private void SetCtlVisible(Control ctl, bool visible)
{
if (ctl.InvokeRequired)
{
SetVisibleCallback d = new SetVisibleCallback(SetCtlVisible);
ctl.Invoke(d, new object[] { ctl, visible });
}
else
{
ctl.Visible = visible;
}
}
Вот некоторые мысли: ли this.InvokeRequired отличаются от ctl.InvokeRequired в любое время? Требуется ли второе испытание InvokeRequired с учетом первого? Необходима ли реализация SetCtlVisible, если я сохраню первый InvokeRequired? Должен ли я удалить первый InvokeRequired и сохранить весь код в предложении else? Нужна ли блокировка вокруг предложения else?
Спасибо, ключ был не полностью загружен, когда поток выполнял LoadReports(). Я также удалил все ненужные вызовы InvokeRequired. – Zamboni