我正在运行BackgroundWorker线程来完成一项耗时的任务。耗时的任务是在另一个班级。我需要将在BackgroundWorker上运行的这个单独的类的进度传递回Main Form1类。我不知道如何处理这个问题。请提供建议。先感谢您。
**// Main Form1 UI Class**
public void backgroundWorker2_DoWork(object sender, DoWorkEventArgs e)
{
//e.Argument always contains whatever was sent to the background worker
// in RunWorkerAsync. We can simply cast it to its original type.
DataSet ds = e.Argument as DataSet;
this.createje.ProcessData(this.ds);
}
private void backgroundWorker2_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
this.progressBar1.Minimum = 0;
this.progressBar1.Maximum = CreateJE.max;
this.progressBar1.Value = e.Recno;
}
**//Other Class called CreateJE**
public void ProcessData(DataSet ds)
{
//Do time consuming task...
for (int i = 1; i <= 10; i++)
{
if (worker.CancellationPending == true)
{
e.Cancel = true;
break;
}
else
{
// Perform a time consuming operation and report progress.
System.Threading.Thread.Sleep(500);
**//How do I report progress back to the Main UI?**
//worker.ReportProgress(i * 10);
}
}
}
答案 0 :(得分:4)
最干净,最可扩展的解决方案可能是让ProcessData()
方法引发BackgroundWorker
正在侦听的事件。这种方式ProcessData()
不依赖于BackgroundWorker
作为调用者。 (你还需要一种取消ProcessData()
)的方法。如果需要,您甚至可以重复使用ProgressChangedEventArgs
。例如(未经测试,但你明白了吗?):
partial class Form1 {
public void backgroundWorker2_DoWork(object sender, DoWorkEventArgs e) {
//e.Argument always contains whatever was sent to the background worker
// in RunWorkerAsync. We can simply cast it to its original type.
DataSet ds = (DataSet)e.Argument;
var bgw = (BackgroundWorker)sender;
var eh = new ProgressChangedEventHandler((o,a) => bgw.ReportProgress(a.ProgressPercentage));
createje.ProgressChanged += eh;
this.createje.ProcessData(this.ds));
createje.ProgressChanged -= eh; //necessary to stop listening
}
private void backgroundWorker2_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
this.progressBar1.Minimum = 0;
this.progressBar1.Maximum = CreateJE.max;
this.progressBar1.Value = e.ProgressPercentage;
}
}
partial class CreateJE {
public event ProgressChangedEventHandler ProgressChanged;
protected virtual void OnProgressChanged(ProgressChangedEventArgs e)
{
var hand = ProgressChanged;
if(hand != null) hand(this, e);
}
public void ProcessData(DataSet ds)
{
for(int i = 1; i <= 10; i++)
{
// Perform a time consuming operation and report progress.
System.Threading.Thread.Sleep(500);
var e = new ProgressChangedEventArgs(i * 10, null);
}
}
}
快速而肮脏的方法是将BackgroundWorker
作为参数传递给ProcessData()
。这是恕我直言,相当丑陋,但是,你只使用BackgroundWorkers,并强迫你在一个地方(主表单类)定义BackgroundWorker
和在另一个地方(CreateJE类)返回ReportProgress的值
您还可以使用计时器并每X ms报告一次进度,查询CreateJE对象的进度。这似乎与您的其余代码一致。与此挂起的是它会使你的CreateJE类不是多线程友好的。
答案 1 :(得分:1)
最快捷,最简单的选择是在类delegate
中声明CreateJE
,报告proggress,然后将其挂钩到ReportProgress
BackgroundWorker
方法。
class CreateJE
{
public Action<int> ReportProgressDelegate{get;set;}
public void ProcessData(DataSet ds)
{
for(int i = 0; i < 10; i++)
{
Thread.Sleep(500);
ReportProgress(i*10);
}
}
private void ReportProgress(int percent)
{
if(ReportProgressDelegate != null)
ReportProgressDelegate(percent);
}
}
在您的表单中,初始化您的实例的ReportProgressDelegate
属性(我假设this.createje
指的是表单的字段,因此OnLoad
似乎是初始化的好地方):< / p>
protected override void OnLoad(EventArgs e)
{
this.creatje.ReportProgressDelegate = worker.ReportProgress;
}
之后,您可以使用已有的事件处理程序(backgroundWorker2_DoWork
和backgroundWorker2_DoWork
)。
PS :您应该对worker.CancellationPending
属性使用相同的方法。