Winform程序需要處理耗時操作時,往往需要將耗時操作放入新開的子線程進行處理,在子線程中可能會經常去修改或操作主線程上的控件;
如果直接在子線程中操作控件,會報線程間操作無效等錯誤,這里提供一個我自己經常使用的跨線程操作方式,代碼如下:
//跨線程操作控件 //(將數據全部裝填完畢后,在一起放到主界面刷新控件;不要一邊裝填一邊刷新主界面控件,這樣依然會導致界面卡頓) public void showMsg(string str) { if (textBox.InvokeRequired) { textBox.Invoke(new Action<string>((s) => { this.textBox.Text = s + "\r\n" + this.textBox.Text; }), str); } else { this.textBox.Text = s + "\r\n" + this.textBox.Text; } }
注意:將數據全部裝填完畢后,在一起放到主界面刷新控件;不要一邊裝填一邊刷新主界面控件,這樣雖然主界面的窗體還能夠移動,依然會導致界面卡頓以及其他控件響應延遲;
比如:在給ListView控件裝填數據時,應先循環把數據全部裝填在一個新建的ListView對象中,然后將新建的ListView對象中的數據利用上述代碼循環拷貝到已有控件中;
以上是自己工作中使用的方法,如果有大神有更好的方法,希望能夠回復,非常接受批評與指導!
以下記錄一下,參考網上寫的一個跨線程操作控件的封裝類,具體如下:
主要為3個方法:Invoke,Get,Set;
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Reflection; using System.Threading.Tasks; using System.Windows.Forms; namespace Common { /// <summary> /// 跨線程調用控件幫助類 /// </summary> public class InvokeHelper { #region delegates private delegate object MethodInvoker(Control control, string methodName, params object[] args); private delegate object PropertyGetInvoker(Control control, object noncontrol, string propertyName); private delegate void PropertySetInvoker(Control control, object noncontrol, string propertyName, object value); #endregion #region static methods // helpers private static PropertyInfo GetPropertyInfo(Control control, object noncontrol, string propertyName) { if (control != null && !string.IsNullOrEmpty(propertyName)) { PropertyInfo pi = null; Type t = null; if (noncontrol != null) t = noncontrol.GetType(); else t = control.GetType(); pi = t.GetProperty(propertyName); if (pi == null) throw new InvalidOperationException( string.Format( "Can't find property {0} in {1}.", propertyName, t.ToString() )); return pi; } else { throw new ArgumentNullException("Invalid argument."); } } /// <summary> /// 調用主界面控件的某個方法,並返回方法執行結果 /// </summary> /// <param name="control"> 控件 </param> /// <param name="methodName"> 方法名 </param> /// <param name="args"> 參數 </param> /// <returns></returns> public static object Invoke(Control control, string methodName, params object[] args) { if (control != null && !string.IsNullOrEmpty(methodName)) { if (control.InvokeRequired) { return control.Invoke( new MethodInvoker(Invoke), control, methodName, args ); } else { MethodInfo mi = null; if (args != null && args.Length > 0) { Type[] types = new Type[args.Length]; for (int i = 0; i < args.Length; i++) { if (args[i] != null) types[i] = args[i].GetType(); } mi = control.GetType().GetMethod(methodName, types); } else mi = control.GetType().GetMethod(methodName); // check method info you get if (mi != null) return mi.Invoke(control, args); else throw new InvalidOperationException("Invalid method."); } } else { throw new ArgumentNullException("Invalid argument."); } } /// <summary> /// 獲取主界面控件的某個屬性 /// </summary> /// <param name="control"> 控件 </param> /// <param name="propertyName"> 屬性名 </param> /// <returns></returns> public static object Get(Control control, string propertyName) { return Get(control, null, propertyName); } public static object Get(Control control, object noncontrol, string propertyName) { if (control != null && !string.IsNullOrEmpty(propertyName)) { if (control.InvokeRequired) { return control.Invoke(new PropertyGetInvoker(Get), control, noncontrol, propertyName ); } else { PropertyInfo pi = GetPropertyInfo(control, noncontrol, propertyName); object invokee = (noncontrol == null) ? control : noncontrol; if (pi != null) if (pi.CanRead) return pi.GetValue(invokee, null); else throw new FieldAccessException( string.Format( "{0}.{1} is a write-only property.", invokee.GetType().ToString(), propertyName )); return null; } } else { throw new ArgumentNullException("Invalid argument."); } } /// <summary> /// 設置主界面控件的某個屬性 /// </summary> /// <param name="control"> 控件 </param> /// <param name="propertyName"> 屬性名 </param> /// <param name="value"> 屬性值 </param> public static void Set(Control control, string propertyName, object value) { Set(control, null, propertyName, value); } public static void Set(Control control, object noncontrol, string propertyName, object value) { if (control != null && !string.IsNullOrEmpty(propertyName)) { if (control.InvokeRequired) { control.Invoke(new PropertySetInvoker(Set), control, noncontrol, propertyName, value ); } else { PropertyInfo pi = GetPropertyInfo(control, noncontrol, propertyName); object invokee = (noncontrol == null) ? control : noncontrol; if (pi != null) if (pi.CanWrite) pi.SetValue(invokee, value, null); else throw new FieldAccessException( string.Format( "{0}.{1} is a read-only property.", invokee.GetType().ToString(), propertyName )); } } else { throw new ArgumentNullException("Invalid argument."); } } #endregion } }