从您的问题看来,您在网格中有多行需要处理。现在后台工作人员在另一个线程中执行该方法,从而释放 UI 以执行其他操作。 (IE 状态更新)。由于这是在另一个线程上执行的,因此 UI 可以正常继续处理。 UI 线程不会等待 BackgroundWorker 完成。如果它确实等待,则使用后台工作人员将毫无用处。此外,BackgroundWorker 必须在开始另一个操作之前完成操作(因此您的错误消息)。
现在很难理解你在 work.doTheWork() 中所做的事情,但我怀疑你会想在这里采取另一种方法。
在我们开始解决这个问题之前,您必须了解的第一件事是后台工作人员的取消实际上并没有取消线程,而是为您的代码提供了一个“标志”来检查 BackgroundWorker 是否正在等待计算 (MSDN on this flag )。
向前迈进。由于 Grid 保存在 UI 线程上,因此您需要了解我们想要捕获的网格中的数据并将其传递到 BackgroundWorker 上下文中。正如这个 inst 提供的,我将做一个非常基本的例子。现在您可以运行多个后台工作人员来单独处理每一行,从而在网格中每行生成 1 个工作人员。对于您的要求,这可能是理想的,但对于较大的网格,您实际上是在每行创建 1 个线程来处理,而在具有数百行的网格中,这可能是灾难性的。
因此,您可以创建如下所示的方法。我已经评论了代码以帮助您完成它。基本上,这显示了取消工作人员、报告进度和单独遍历每个行项目的能力。我还添加了一些基本类以供在工作人员内部使用。 [注意这只是演示代码]
class DoWorkTester
{
int currentIndex = 0;
GridRow[] rows;
public void ExecuteWorkers()
{
GridRow rowA = new GridRow
{
PropertyA = "abc",
PropertyB = "def"
};
GridRow rowB = new GridRow
{
PropertyA = "123",
PropertyB = "456"
};
GridRow rowC = new GridRow
{
PropertyA = "xyz",
PropertyB = "789"
};
rows = new GridRow[] { rowA, rowB, rowC };
currentIndex = 0;
runWorkers();
}
BackgroundWorker worker;
void runWorkers()
{
//done all rows
if (currentIndex >= rows.Length - 1)
return;
//is the worker busy?
if (worker != null && worker.IsBusy)
{
//TODO: Trying to execute on a running worker.
return;
}
//create a new worker
worker = new BackgroundWorker();
worker.WorkerSupportsCancellation = true;
worker.WorkerReportsProgress = true;
worker.ProgressChanged += (o, e) =>
{
//TODO: Update the UI that the progress has changed
};
worker.DoWork += (o, e) =>
{
if (currentIndex >= rows.Length - 1)
{
//indicate done
e.Result = new WorkResult
{
Message = "",
Status = WorkerResultStatus.DONE
};
return;
}
//check if the worker is cancelling
else if (worker.CancellationPending)
{
e.Result = WorkResult.Cancelled;
return;
}
currentIndex++;
//report the progress to the UI thread.
worker.ReportProgress(currentIndex);
//TODO: Execute your logic.
if (worker.CancellationPending)
{
e.Result = WorkResult.Cancelled;
return;
}
e.Result = WorkResult.Completed;
};
worker.RunWorkerCompleted += (o, e) =>
{
var result = e.Result as WorkResult;
if (result == null || result.Status != WorkerResultStatus.DONE)
{
//TODO: Code for cancelled \ failed results
worker.Dispose();
worker = null;
return;
}
//Re-call the run workers thread
runWorkers();
};
worker.RunWorkerAsync(rows[currentIndex]);
}
/// <summary>
/// cancel the worker
/// </summary>
void cancelWorker()
{
//is the worker set to an instance and is it busy?
if (worker != null && worker.IsBusy)
worker.CancelAsync();
}
}
enum WorkerResultStatus
{
DONE,
CANCELLED,
FAILED
}
class WorkResult
{
public string Message { get; set; }
public WorkerResultStatus Status { get; set; }
public static WorkResult Completed
{
get
{
return new WorkResult
{
Status = WorkerResultStatus.DONE,
Message = ""
};
}
}
public static WorkResult Cancelled
{
get
{
return new WorkResult
{
Message = "Cancelled by user",
Status = WorkerResultStatus.CANCELLED
};
}
}
}
class GridRow
{
public string PropertyA { get; set; }
public string PropertyB { get; set; }
}
现在,如果您想一次处理多行,则必须调整代码以使用某种 Worker Pooling 或将所有行数据传递给第一个后台 Worker,从而消除递归。
干杯。