目录
介绍
背景
使用代码
兴趣点
有许多使用BackgroundWorker的方法:lambda、匿名委托和事件。所有这些都有优点和缺点,但我发现它们可读性较差。在这里,您将看到使用BackgroundWorker的另一种方法。
介绍本技巧的目的是展示一种替代的使用BackgroundWorker方法。
背景Microsoft文档显示了如何与事件一起使用BackgroundWorker,在这些示例中,可以使用其他方法。
BackgroundWorker bgw = new BackgroundWorker();
bgw.DoWork += new DoWorkEventHandler(
() =>
{
// Do Something
}
);
bgw.DoWork += (sender, e) => { ... }
bgw.DoWork += delegate { ... }
我发现这些方法不太容易理解,因此建议在下一章中使用该方法。
public class PatientMan
{
private Action _DoWork = null;
private Boolean _IsDoWorkSubscribe = false;
private DoWorkEventHandler _DoWorkHandler;
private Action _RunWorkerCompleted = null;
private Boolean _IsRunWorkerCompletedSubscribe = false;
private RunWorkerCompletedEventHandler _RunWorkerCompletedHandler;
private Action _ProgressChanged = null;
private Boolean _IsProgressChangedSubscribe = false;
private ProgressChangedEventHandler _ProgressChangedHandler;
private BackgroundWorker _Worker = new BackgroundWorker();
public PatientMan()
{
}
public PatientMan(Action doWorkAction,
Action runWorkerCompleted)
{
this.SubcribeDoWork(doWorkAction);
this.SubcribeRunWorkerCompleted(runWorkerCompleted);
}
private void SubcribeDoWork(Action doWorkAction)
{
this._DoWork = doWorkAction;
this._DoWorkHandler = delegate { this._DoWork(); };
this._Worker.DoWork += _DoWorkHandler;
this._IsDoWorkSubscribe = true;
}
private void SubcribeRunWorkerCompleted(Action runWorkerCompleted)
{
this._RunWorkerCompleted = runWorkerCompleted;
this._RunWorkerCompletedHandler
=
delegate {
this._RunWorkerCompleted();
this.UnsubscribeEvents();
};
this._Worker.RunWorkerCompleted += this._RunWorkerCompletedHandler;
this._IsRunWorkerCompletedSubscribe = true;
}
private void SubcribeProgressChanged(Action progressChanged)
{
this._ProgressChanged = progressChanged;
this._ProgressChangedHandler = (obj, ev) =>
{
this._ProgressChanged(ev.ProgressPercentage);
};
this._Worker.ProgressChanged += this._ProgressChangedHandler;
this._Worker.WorkerReportsProgress = true;
this._IsProgressChangedSubscribe = true;
}
public void RunWorkerAsync()
{
this._Worker.RunWorkerAsync();
}
public void ReportProgress(int percentage)
{
if(this._ProgressChanged != null)
{
if (this._IsProgressChangedSubscribe == true)
{
this._Worker.ReportProgress(percentage);
}
else
{
throw new ArgumentNullException();
}
}
else
{
throw new NullReferenceException();
}
}
private void UnsubscribeEvents()
{
if (this._IsDoWorkSubscribe == true)
{
this._Worker.DoWork -= this._DoWorkHandler;
this._IsDoWorkSubscribe = false;
}
if (this._IsRunWorkerCompletedSubscribe == true)
{
this._Worker.RunWorkerCompleted -= this._RunWorkerCompletedHandler;
this._IsRunWorkerCompletedSubscribe = false;
}
if (this._IsProgressChangedSubscribe == true)
{
this._Worker.ProgressChanged -= this._ProgressChangedHandler;
this._Worker.WorkerReportsProgress = false;
this._IsProgressChangedSubscribe = false;
}
}
public void Dispose()
{
this.UnsubscribeEvents();
this._Worker.Dispose();
}
public void SetEvents(Action doWorkAction,
Action runWorkerCompleted,
Action progressChanged,
Boolean unsubscribeEvents = false)
{
this.UnsubscribeEvents();
this.SubcribeDoWork(doWorkAction);
this.SubcribeRunWorkerCompleted(runWorkerCompleted);
this.SubcribeProgressChanged(progressChanged);
}
}
PatientMan类提供了包装BackgroundWorker的基本功能。
可以通过以下方式使用它:
public class SandBoxPatientMan
{
public SandBoxPatientMan(int algo)
{
switch(algo)
{
case 0:
{
Action doWork = delegate
{
// Do something long
for (int i = 0; i < 10; i++)
{
System.Threading.Thread.Sleep(1000);
}
};
Action runWorkerCompleted = delegate
{
// Do something after you did something long
Console.WriteLine("runWorkerCompleted " + algo);
};
PatientMan patientMan = new PatientMan(doWork, runWorkerCompleted);
patientMan.RunWorkerAsync();
}
break;
case 1:
{
PatientMan patientMan = new PatientMan();
Action doWork = delegate
{
// Do something long
for (int i = 0; i < 10; i++)
{
System.Threading.Thread.Sleep(1000);
patientMan.ReportProgress(i);
}
};
Action runWorkerCompleted = delegate
{
// Do something after you did something long
Console.WriteLine("runWorkerCompleted " + algo);
};
Action progressChanged = (percentage) =>
{
// Report a progress during a long process
Console.WriteLine("progressChanged " + percentage);
};
patientMan.SetEvents(doWork, runWorkerCompleted, progressChanged);
patientMan.RunWorkerAsync();
}
break;
}
}
}
通过参数传递委托更加可读和简洁。
以我的经验,它也更容易调试。
兴趣点此类不能替代完全的BackgroundWorker,它需要一些更新如Cancellation或诸IsBusy。