尝试获取comboBox的值时,“跨线程操作无效”exception

"Cross-thread operation is not valid" exception 

我经历了很多次此exception,但所有那些时候我都在设置控件的值。 那时我解决了使用一个名为SetControlPropertyThreadSafe()的函数,该函数仅由stackoverflow.com上的某人建议。 但是这次我在尝试获取comboBox的值时遇到此exception。 这是代码:

  string cat; private void button1_Click(object sender, EventArgs e) { if (textBox1.Text.Trim().Length > 20) { System.Threading.Thread t = new System.Threading.Thread(addQuickTopic); t.Start(); } else MessageBox.Show("The length of the title must be greater than 20", "Title length invalid", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); } public string tTitle=""; void addQuickTopic() { Global.SetControlPropertyThreadSafe(button1, "Text", "Working..."); Global.SetControlPropertyThreadSafe(button1, "Enabled", false); Topic t = new Topic(); t.setTitle(textBox1.Text); t.setDescription(" "); t.setDesID(Global.getMd5Hash(Common.uid+DateTime.Today.ToString()+DateTime.Today.Millisecond.ToString())); t.setUsrID(Common.uid); t.setReplyToID(""); t.setConDate("0"); cat = CategoryList.SelectedValue.ToString(); 

正如您所看到的,我直接获取textBox1.Text而不应用任何线程安全操作。 但是在最后一行尝试获取comboBox的选定值时,我得到了这个exception。 所以任何人都可以建议我在这种情况下做什么? 以下是我的线程安全function的代码,用于设置控件的值:

 public static void SetControlPropertyThreadSafe(Control control, string propertyName, object propertyValue) { try { if (control.InvokeRequired) { control.Invoke(new SetControlPropertyThreadSafeDelegate(SetControlPropertyThreadSafe), new object[] { control, propertyName, propertyValue }); } else { control.GetType().InvokeMember(propertyName, BindingFlags.SetProperty, null, control, new object[] { propertyValue }); } } catch (Exception) { } } 

我是否需要创建类似的get函数? 或任何其他解决方案?

现在,您从TextBox获取值,通过: t.setTitle(textBox1.Text); 。 这也将失败。

我是否需要创建类似的get函数? 或任何其他解决方案?

是的,你需要一个选择。 但是,我建议不要使用reflection和文本,并将其重新设计为使用generics方法和lambdas。

 public static void SetControlPropertyThreadSafe(T control, Action action) where T : Control { if (control.InvokeRequired) { control.Invoke(action); } else { action(); } } 

这将允许你写这个强类型,即:

 Global.SetControlPropertyThreadSafe(button1, b => b.Text = "Working..."); 

您还可以创建一个强类型的get方法:

 public static U GetControlPropertyThreadSafe(T control, Func func) where T : Control { if (control.InvokeRequired) { return (U)control.Invoke(func, new object[] {control}); } else { return func(control); } } 

然后让你写:

  t.setTitle(Global.GetControlPropertyThreadSafe(textBox1, t => t.Text)); 

您还可以使用相同的方法来获取和设置combobox项。

您需要一个类似的get函数,如果需要,它会调用Invoke。 这取决于GUI的线程模型,该模型声明与GUI交互的所有方法只应由GUI线程调用。

如果你正在尝试阅读,写作或做任何其他事情,这并不重要。 如果您不在GUI线程上,则必须使用Invoke。