Я долго боролся с этим:
У меня есть функция, предназначенная для добавления элемента управления на панель с межпотоковой обработкой, проблема в том, что хотя панель и элемент управления находятся в «InvokeRequired = false» - я получаю исключение, сообщающее мне, что к одному из внутренних элементов управления элементов управления обращаются из потока, отличного от потока, в котором он был создан, фрагмент выглядит следующим образом:
public delegate void AddControlToPanelDlgt(Panel panel, Control ctrl);
public void AddControlToPanel(Panel panel, Control ctrl)
{
if (panel.InvokeRequired)
{
panel.Invoke(new AddControlToPanelDlgt(AddControlToPanel),panel,ctrl);
return;
}
if (ctrl.InvokeRequired)
{
ctrl.Invoke(new AddControlToPanelDlgt(AddControlToPanel),panel,ctrl);
return;
}
panel.Controls.Add(ctrl); //<-- here is where the exception is raised
}
сообщение об исключении выглядит следующим образом:
"Операция с несколькими потоками недопустима: элемент управления 'pnlFoo' доступен из потока, отличного от потока, в котором он был создан"
(pnlFoo находится под управлением ctrl.Controls)
Как мне добавить ctrl на панель?!
Когда код достигает «panel.Controls.Add (ctrl);» line - для свойства InvokeRequired панели и ctrl задано значение false, проблема заключается в том, что для элементов управления внутри ctrl значение InvokeRequired установлено в значение true. Чтобы прояснить ситуацию: «панель» создается в базовом потоке, а «ctrl» - в новом потоке, поэтому необходимо вызывать «панель» (что вызывает необходимость повторного вызова «ctrl»). Как только оба вызова завершены, он достигает команды panel.Controls.Add (ctrl) (в этом состоянии не нужно вызывать и "panel", и "ctrl")
Вот небольшой фрагмент полной программы:
public class ucFoo : UserControl
{
private Panel pnlFoo = new Panel();
public ucFoo()
{
this.Controls.Add(pnlFoo);
}
}
public class ucFoo2 : UserControl
{
private Panel pnlFooContainer = new Panel();
public ucFoo2()
{
this.Controls.Add(pnlFooContainer);
Thread t = new Thread(new ThreadStart(AddFooControlToFooConatiner());
t.Start()
}
private AddFooControlToFooConatiner()
{
ucFoo foo = new ucFoo();
this.pnlFooContainer.Controls.Add(ucFoo); //<-- this is where the exception is raised
}
}