What happens if the long running task that needs to execute in the background must run in a Single Threaded Apartment? This might happen if you're doing image processing and the library that handles the heavy lifting is an ActiveX control.
Since it has a visual representation it must run in a Single Threaded Apartment. But BackgroundWorker does it's background work on a thread that does not run in a Single Threaded Apartment.
To address this I wrote a shameless rip of BackgroundWorker. The only significant difference is that it does its background work on a thread that runs in a single threaded apartment.
Hopefully the .NET devs won't mind. Imitation is the sincerest form of flattery.
A colorized and formatted version of the code below for StaBackgroundWorker can be found here.
/// <summary>
/// Similar to BackgroundWorker except that it does its work on a Single Threaded Apartment thread.
/// </summary>
public class StaBackgroundWorker
{
public event System.ComponentModel.DoWorkEventHandler DoWork;
public event System.ComponentModel.ProgressChangedEventHandler ProgressChanged;
public event System.ComponentModel.RunWorkerCompletedEventHandler RunWorkerCompleted;
private Control creatorControl;
public StaBackgroundWorker(Control creatorControl)
{
this.creatorControl = creatorControl;
}
public void RunWorkerAsync()
{
RunWorkerAsync(null);
}
public void RunWorkerAsync(object userState)
{
Thread staThread = new Thread(new ParameterizedThreadStart(RunWorkerAsyncThreadFunc));
staThread.SetApartmentState(ApartmentState.STA);
staThread.Start(userState);
}
private void RunWorkerAsyncThreadFunc(object userState)
{
DoWorkEventArgs doWorkEventArgs = new DoWorkEventArgs(userState);
Exception doWorkException = null;
try
{
OnDoWork(doWorkEventArgs);
}
catch (Exception ex)
{
doWorkException = ex;
}
RunWorkerCompletedEventArgs workerCompletedEventArgs =
new RunWorkerCompletedEventArgs(doWorkEventArgs.Result, doWorkException, doWorkEventArgs.Cancel);
creatorControl.Invoke(new MethodInvoker(delegate() { OnRunWorkerCompleted(workerCompletedEventArgs); }));
}
protected virtual void OnDoWork(DoWorkEventArgs e)
{
if (DoWork != null)
DoWork(this, e);
}
private bool cancellationPending;
public bool CancellationPending
{
get { return cancellationPending; }
}
public void CancelAsync()
{
cancellationPending = true;
}
public void ReportProgress(int percentComplete, object userState)
{
ProgressChangedEventArgs e = new ProgressChangedEventArgs(percentComplete, userState); // marshal this call onto the thread that created the control that created us
creatorControl.Invoke(new MethodInvoker(delegate() { OnProgressChanged(e); }));
}
protected virtual void OnProgressChanged(ProgressChangedEventArgs e)
{
if (ProgressChanged != null)
ProgressChanged(this, e);
}
protected virtual void OnRunWorkerCompleted(RunWorkerCompletedEventArgs e)
{
if (RunWorkerCompleted != null)
RunWorkerCompleted(this, e);
}
}
No comments:
Post a Comment