解决WinForms中的跨线程exception

目前我正在使用WinForms(在C#中),我必须在后台运行该应用程序。 为此,我使用异步。 当我运行应用程序时,它显示了一个例外

“跨线程操作无效:控制”从其创建的线程以外的线程访问。”

我该如何解决这个错误?

在对控件进行方法调用时,如果调用者与创建控件的线程不在同一个线程上,则需要使用Control.Invoke进行调用。 这是一个代码示例:

// you can define a delegate with the signature you want public delegate void UpdateControlsDelegate(); public void SomeMethod() { //this method is executed by the background worker InvokeUpdateControls(); } public void InvokeUpdateControls() { if (this.InvokeRequired) { this.Invoke(new UpdateControlsDelegate(UpdateControls)); } else { UpdateControls(); } } private void UpdateControls() { // update your controls here } 

希望能帮助到你。

大多数情况下,使用WinForms执行此类操作的最佳方法是使用BackgroundWorker ,它将在后台线程上运行您的工作,但为您提供了一种将状态报告回UI的简洁方法。

在很多日常的.NET编程中,显式创建线程或调用.Invoke表明你没有充分利用框架(当然,有很多合理的理由去做低级的东西,它是只是他们不太常见,人们有时会意识到)。

您需要检查您尝试更新的控件是否需要调用。 像这样的东西:

 Action setterCallback = (toSet, text) => toSet.Text = text; void SetControlText(Control toSet, string text) { if (this.InvokeRequired) { this.Invoke(setterCallback, toSet, text); } else { setterCallback(toSet, text); } } 

您可能会发现有用的模式是在与GUI交互的函数顶部进行检查,以查看您是否在正确的线程上运行,并在需要时让函数自行调用。 像这样:

  public delegate void InvocationDelegate(); public void DoGuiStuff(){ if (someControl.InvokeRequired){ someControl.Invoke(InvocationDelegate(DoGuiStuff)); return; } //GUI manipulation here } 

使用这种模式 – 如果在调用方法时你在正确的线程上它不会自己调用,但是如果你在不同的线程上它将自己调用然后返回(所以GUI操作逻辑只被调用过一次办法)。

从Invoke更新以开始Invoke

 // you can define a delegate with the signature you want public delegate void UpdateControlsDelegate(); public void SomeMethod() { //this method is executed by the background worker InvokeUpdateControls(); } public void InvokeUpdateControls() { if (this.InvokeRequired) { this.BeginInvoke(new UpdateControlsDelegate(UpdateControls)); } else { UpdateControls(); } } private void UpdateControls() { // update your controls here } 

可以使用Control.Invoke()方法完成UI更改,可以使用下面的代码片段解决此跨线程exception。

 void UpdateWorker() { //Here ddUser is the user control //Action to be performed should be called within { } as like below code if (this.ddUser.InvokeRequired) ddUser.Invoke(new MethodInvoker(() => { ddUser.Size = new Size(100, 100); })); }