我知道有很多关于我的问题的topcis,但我无法找到解决方案......
我有一个面板,我在运行时添加了控件,我尝试了这段代码,但它没有帮助我,并且错误说:
跨线程操作无效控制' panel1'从一个线程访问 除了在
上创建的主题
这是我的代码:
public void AddControlToPanel(Panel panel, Control ctrl)
{
if (panel.InvokeRequired)
{
panel.Invoke((MethodInvoker)delegate { AddControlToPanel(panel, ctrl); });
return;
}
else
panel.Controls.Add(ctrl);
}
我称之为:
AddControlToPanel(panel1, ctrl);
答案 0 :(得分:2)
您可以在项目的命名空间中创建一个控件扩展名,如下所示:
public static class ControlExtensions
{
public static void UIThread(this Control @this, Action code)
{
if (null != @this && (!@this.Disposing || !@this.IsDisposed))
{
if (@this.InvokeRequired)
{
@this.BeginInvoke(code);
}
else
{
code.Invoke();
}
}
}
}
并在您的代码中使用它,如下所示:
this.UIThread(() =>
{
panel1.Controls.Add(ctrl);
});
答案 1 :(得分:0)
在这种情况下,您还应该检查" IsHandleCreated"
来自MSDN的: ...如果不需要Invoke(调用发生在同一个线程上),或者如果控件是在另一个线程上创建但尚未创建控件的句柄,则InvokeRequired可以返回false。
...
当InvokeRequired在后台线程上返回false时,还可以通过检查IsHandleCreated的值来防止这种情况。如果尚未创建控件句柄,则必须等到创建它之后再调用Invoke或BeginInvoke。通常,只有在应用程序的主要表单的构造函数中创建后台线程(如在Application.Run(new MainForm())中,在显示表单或调用Application.Run之前,才会发生这种情况。
答案 2 :(得分:0)
最终我解决了我的问题,我的代码是正确的,只是隐藏旧的控件来显示新的,使用这个很好的功能:
private void SetControlPropertyValue(Control oControl, string propName, object propValue)
{
if (oControl.InvokeRequired)
{
SetControlValueCallback d = new SetControlValueCallback(SetControlPropertyValue);
oControl.Invoke(d, new object[] { oControl, propName, propValue });
}
else
{
Type t = oControl.GetType();
PropertyInfo[] props = t.GetProperties();
foreach (PropertyInfo p in props)
{
if (p.Name.ToUpper() == propName.ToUpper())
{
p.SetValue(oControl, propValue, null);
}
}
}
}
像这样:
foreach (Control item in panel1.Controls.OfType<Type>())
{
SetControlPropertyValue(item, "Visible", false);
}
然后,我可以像这样重新创建我的控件:
AddControlToPanel(panel1, ctrl);
感谢大家的帮助:)