C#如何从后台线程向控件的Controls属性添加新控件?
问题解决方法
报错原因
你直接用InvokeMember("Controls.Add")是错误的——Controls是控件的属性,不是方法,Add是Controls属性对应的Control.ControlCollection集合的方法,不能直接通过控件类型调用"Controls.Add"这个不存在的方法。
修正InvokeMember的写法
如果一定要保留InvokeMember的用法,需要分两步执行:先获取Controls属性值,再调用该集合的Add方法:
private delegate void AddControlThreadSafeDelegate(Control newControl, Control parent); public static void AddControlThreadSafe(Control newControl, Control parent) { if (newControl == null) return; if (parent == null) return; if (parent.InvokeRequired) { parent.Invoke(new AddControlThreadSafeDelegate(AddControlThreadSafe), new object[] { newControl, parent }); } else { // 第一步:获取Controls属性实例 var controlsCollection = parent.GetType() .InvokeMember("Controls", BindingFlags.GetProperty, null, parent, null) as Control.ControlCollection; // 第二步:调用集合的Add方法 controlsCollection?.InvokeMember("Add", BindingFlags.InvokeMethod, null, controlsCollection, new object[] { newControl }); } }
更简洁的常规写法
实际上在else分支里,已经确认处于UI线程,完全没必要用InvokeMember,直接调用控件的方法即可,代码更简洁易读:
private delegate void AddControlThreadSafeDelegate(Control newControl, Control parent); public static void AddControlThreadSafe(Control newControl, Control parent) { if (newControl == null || parent == null) return; if (parent.InvokeRequired) { parent.Invoke(new AddControlThreadSafeDelegate(AddControlThreadSafe), newControl, parent); } else { parent.Controls.Add(newControl); } }
简化线程安全调用的写法
可以省略显式定义委托,用MethodInvoker结合Lambda表达式进一步简化代码,同时Invoke方法本身会自动处理InvokeRequired的判断(如果不需要跨线程调用,Invoke会直接执行):
public static void AddControlThreadSafe(Control newControl, Control parent) { if (newControl == null || parent == null) return; parent.Invoke((MethodInvoker)(() => { parent.Controls.Add(newControl); })); }
内容的提问来源于stack exchange,提问作者RANGO
相关产品推荐
相关产品推荐

