我有一个WinForm和一个backgroundWorker:
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();
}
}
}我第一次运行这个很好。但是当我第二次打电话给InvalidOperationException时,我得到了this.Hide()。
“附加信息:跨线程操作无效:从创建线程的线程以外的线程访问控件'UIProgress‘。”
奇怪的是,在第一次运行foo时,Start()是一个WindowsFormsSyncronizationContext,但是在第二次尝试中,它是一个System.Threading.SyncronizationContext.
我正在编写的应用程序是一个ExcelDna插件。
编辑
Start()的调用如下:
UIProgress uiProgress = new UIProgress(
delegate(object sender, DoWorkEventArgs args)
{
....
},
delegate(object sender, RunWorkerCompletedEventArgs args)
{
...
}
);
uiProgress.Start();发布于 2014-12-07 15:39:08
必须从运行在UI线程上的代码中调用Start()方法,以允许BackgroundWorker正确操作。不是当你得到这个例外的时候。将保护代码添加到您的方法中,以便您可以诊断此事故:
public void Start()
{
if (Thread.CurrentThread.GetApartmentState() != ApartmentState.STA) {
throw new InvalidOperationException("Bug! Code called from a worker thread");
}
backgroundWorker.RunWorkerAsync();
}现在,您可以在抛出语句上设置一个断点,并使用调试器的Call Stack窗口来找出发生这种情况的原因。
发布于 2014-12-15 10:58:17
您正在调用后台线程上的UI操作。这就是这种例外的原因。我会使用完全不同的方法来完成进度,最好的方法是在IProgress中使用任务。另一种使用方式是:
private void backgroundWorker_ProgressChanged( object sender , ProgressChangedEventArgs e )
{
this.UpdateOnMainThread(
( ) =>
{
wdgProgressBar.Value = e.ProgressPercentage;
if ( this.Visible == false )
{
this.ShowDialog( );
this.Update( );
}
} );
}
private void UpdateOnMainThread( Action action )
{
if ( this.InvokeRequired )
{
this.BeginInvoke( ( MethodInvoker ) action.Invoke);
}
else
{
action.Invoke( );
}
}
private void backgroundWorker_RunWorkerCompleted( object sender , RunWorkerCompletedEventArgs e )
{
this.UpdateOnMainThread(
( ) =>
{
this.Hide( ); //Here I get a InvalidOperationException
this.Dispose( );
} );
}发布于 2014-12-11 03:00:46
在表单上使用BeginInvoke()方法:
//http://msdn.microsoft.com/en-us/library/0b1bf3y3(v=vs.110).aspx
private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
this.BeginInvoke(new InvokeDelegate(InvokeMethod));
}
public delegate void InvokeDelegate();
public void InvokeMethod()
{
this.Hide();
this.Dispose();
}https://stackoverflow.com/questions/27344054
复制相似问题