我有一个带有backgroundWorker的WinForm:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using SEOTools.Utils; namespace SEOTools.UI { public partial class UIProgress : Form { public UIProgress(DoWorkEventHandler doWorkEventHandler,RunWorkerCompletedEventHandler runWorkerCompletedEventHandler) { InitializeComponent(); this.backgroundWorker.WorkerReportsProgress = true; this.backgroundWorker.WorkerSupportsCancellation = true; this.backgroundWorker.DoWork += doWorkEventHandler; this.backgroundWorker.RunWorkerCompleted += runWorkerCompletedEventHandler; } public void Start() { var foo = SynchronizationContext.Current; backgroundWorker.RunWorkerAsync(); } private void btnStop_Click(object sender,EventArgs e) { btnStop.Enabled = false; btnStop.Text = "Stopping..."; backgroundWorker.CancelAsync(); } private void backgroundWorker_ProgressChanged(object sender,ProgressChangedEventArgs e) { try { wdgProgressBar.Value = e.ProgressPercentage; if (this.Visible == false) { this.ShowDialog(); this.Update(); } } catch (InvalidOperationException) {} } private void backgroundWorker_RunWorkerCompleted(object sender,RunWorkerCompletedEventArgs e) { this.Hide(); //Here I get a InvalidOperationException this.Dispose(); } } }
我第一次运行它运行正常.但是第二次调用this.Hide()时我得到InvalidOperationException.
“Additional information: Cross-thread operation not valid: Control ‘UIProgress’ accessed from a thread other than the thread it was created on.”
奇怪的是第一次运行foo在Start()中是一个WindowsFormsSyncronizationContext,但在第二次尝试它是一个System.Threading.SyncronizationContext.
我正在编写的应用程序是一个ExcelDna插件.
编辑
Start()被调用如下:
UIProgress uiProgress = new UIProgress( delegate(object sender,DoWorkEventArgs args) { .... },delegate(object sender,RunWorkerCompletedEventArgs args) { ... } ); uiProgress.Start();
解决方法
必须从在UI线程上运行的代码调用Start()方法,以允许BackgroundWorker正常运行.这不是你得到这个例外的时候.为您的方法添加保护代码,以便您可以诊断此事故:
public void Start() { if (Thread.CurrentThread.GetApartmentState() != ApartmentState.STA) { throw new InvalidOperationException("Bug! Code called from a worker thread"); } backgroundWorker.RunWorkerAsync(); }
现在,您可以在throw语句上设置断点,并使用调试器的“调用堆栈”窗口来查找发生这种情况的原因.