跨线程操作不是有效的控件
本文关键字:有效 控件 线程 操作 | 更新日期: 2023-09-27 18:00:34
我知道关于我的问题有很多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);
您可以在项目的命名空间中创建一个控件扩展,如下所示:
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);
});
在这种情况下,您还应该检查"IsHandleCreated"
来自MSDN:…如果不需要Invoke(调用发生在同一线程上),或者控件是在不同线程上创建的,但控件的句柄尚未创建,则InvokeRequired可能返回false。
当InvokeRequired在后台线程上返回false时,还可以通过检查IsHandleCreated的值来防止这种情况。如果尚未创建控件句柄,则必须等到创建控件句柄后才能调用Invoke或BeginInvoke。通常,只有在显示窗体或调用application.Run之前,在应用程序的主窗体的构造函数中创建了后台线程(如application.Run(new MainForm())),才会发生这种情况。
最终我解决了我的问题,我的代码是正确的,只是使用这个漂亮的函数隐藏旧控件以显示新控件:
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);
感谢所有人的帮助:)