BackgroundWorker - 使用 "sub tasks" 报告进度
BackgroundWorker - reporting progress with "sub tasks"
带有自定义控件的 WinForms 应用程序 LabelProgressBar
,它能够显示进度和一些描述性文本 and/or 完成百分比。这是通过调用 LabelProgressBar.statusInProgress(string message, int percentageCompletion)
.
完成的
其用法如下:
private void import_begin(System.Object sender, System.ComponentModel.DoWorkEventArgs args)
{
// first unpack the arguments
System.Object[] arguments = (System.Object[])args.Argument;
System.String filename = (System.String)arguments[0];
System.String why = (System.String)arguments[1];
// tasks:
// 1. read excel file and apply changes to model
// 2. gather changes and format them as XML
// 3. send request to server
// 4. commit/rollback changes
// grab the worker thread so we can report percentage progress
System.ComponentModel.BackgroundWorker worker = (System.ComponentModel.BackgroundWorker)sender;
// now do the work
#region Task1
Controller.Excel excel = new Controller.Excel(filename);
try
{
// the progress of this needs to be tracked
overall_result = excel.import_all(out modified_nodes);
}
catch (InvalidDataExcetpion invDataEx)
{
// deal with it
}
#endregion
worker.ReportProgress(25);
// complete remaining tasks...
}
工作人员报告其进度的事件处理程序如下:
private void import_progress(object sender, System.ComponentModel.ProgressChangedEventArgs e)
{
Debug.WriteLine("Import percentage completion: " + e.ProgressPercentage);
labelProgressBar1.statusInProgress("Import", e.ProgressPercentage);
}
简而言之,import_begin
方法被分解成几个"tasks"。这些被分解为 "subtasks"。以import_all
方法为例:
public Command_Result import_all(out System.Collections.Generic.List<Model.Data_Node> nodes)
{
Command_Result overall_result = Command_Result.OK;
Command_Result this_result;
nodes = new System.Collections.Generic.List<Model.Data_Node>(excel.Workbook.Worksheets.Count);
Model.Data_Node destination;
// the intent is to report the progress of this particular subtask on the basis of how many worksheets have been processed in this for loop
foreach (OfficeOpenXml.ExcelWorksheet worksheet in excel.Workbook.Worksheets)
{
this_result = import_sheet(worksheet.Name, out destination);
nodes.Add(destination);
if (this_result > overall_result)
{
overall_result = this_result;
}
}
return overall_result;
}
目的是让此 "subtask" 根据循环中已处理的工作表数量报告进度。为此计算百分比是一项微不足道的任务,但我不清楚如何将其报告回 import_begin
方法。当这个"subtask"完成后,总体任务完成度(从import_begin
方法的POV)应该是25%。其他任务也类似。如何实现?
import_begin
其实不需要获取更新,直接调用子任务即可,而也传递了BackgroundWorker
,所以子任务负责直接报告他们的进展。如果 "polluting" 带有 BackgroundWorker
的子任务不可接受,则创建一个委托来调用 BackgroundWorker,这样您的子任务就会调用委托。
private void mainTask(object sender, DoWorkEventArgs e)
{
var worker = (BackgroundWorker)sender;
var report = new Action<int>(i => worker.ReportProgress(i)); //the delegate
smallTask1Clean(report); //this one pass the delegate
smallTask2(worker); //this one directly call background worker
worker.ReportProgress(100);
}
void smallTask1Clean(Action<int> a)
{
for (int i = 0; i < 20; i++)
{
Thread.Sleep(500);
a(i);
}
}
void smallTask2(BackgroundWorker w)
{
for (int i = 0; i < 5; i++)
{
Thread.Sleep(1000);
w.ReportProgress(i*80/5+20);
}
}
您还可以将子任务隔离开来,使其不必知道它们在较大任务中的作用,在这种情况下,委托应采用两个变量,即子任务的当前内部进度和它需要处理的总项目。
private void mainTask(object sender, DoWorkEventArgs e)
{
var worker = (BackgroundWorker)sender;
var preTaskProgress = 0;
var currentTaskTotalPercentage = 0;
var smarterDelegate = new Action<int, int>((current, total) =>
{
worker.ReportProgress(preTaskProgress + (current *currentTaskTotalPercentage/total));
});
currentTaskTotalPercentage = 30; //the following task will in total progressed the main task for 30%
smallTaskClean(smarterDelegate);
preTaskProgress = currentTaskTotalPercentage; //upate the main the progress before starting the next task
currentTaskTotalPercentage = 70; //the following task will in total progressed the main task for 70%
smallTaskClean(smarterDelegate);
worker.ReportProgress(100);
}
void smallTaskClean(Action<int,int> a)
{
for (int i = 0; i < 5; i++)
{
Thread.Sleep(1500);
a(i,5);
}
}
带有自定义控件的 WinForms 应用程序 LabelProgressBar
,它能够显示进度和一些描述性文本 and/or 完成百分比。这是通过调用 LabelProgressBar.statusInProgress(string message, int percentageCompletion)
.
其用法如下:
private void import_begin(System.Object sender, System.ComponentModel.DoWorkEventArgs args)
{
// first unpack the arguments
System.Object[] arguments = (System.Object[])args.Argument;
System.String filename = (System.String)arguments[0];
System.String why = (System.String)arguments[1];
// tasks:
// 1. read excel file and apply changes to model
// 2. gather changes and format them as XML
// 3. send request to server
// 4. commit/rollback changes
// grab the worker thread so we can report percentage progress
System.ComponentModel.BackgroundWorker worker = (System.ComponentModel.BackgroundWorker)sender;
// now do the work
#region Task1
Controller.Excel excel = new Controller.Excel(filename);
try
{
// the progress of this needs to be tracked
overall_result = excel.import_all(out modified_nodes);
}
catch (InvalidDataExcetpion invDataEx)
{
// deal with it
}
#endregion
worker.ReportProgress(25);
// complete remaining tasks...
}
工作人员报告其进度的事件处理程序如下:
private void import_progress(object sender, System.ComponentModel.ProgressChangedEventArgs e)
{
Debug.WriteLine("Import percentage completion: " + e.ProgressPercentage);
labelProgressBar1.statusInProgress("Import", e.ProgressPercentage);
}
简而言之,import_begin
方法被分解成几个"tasks"。这些被分解为 "subtasks"。以import_all
方法为例:
public Command_Result import_all(out System.Collections.Generic.List<Model.Data_Node> nodes)
{
Command_Result overall_result = Command_Result.OK;
Command_Result this_result;
nodes = new System.Collections.Generic.List<Model.Data_Node>(excel.Workbook.Worksheets.Count);
Model.Data_Node destination;
// the intent is to report the progress of this particular subtask on the basis of how many worksheets have been processed in this for loop
foreach (OfficeOpenXml.ExcelWorksheet worksheet in excel.Workbook.Worksheets)
{
this_result = import_sheet(worksheet.Name, out destination);
nodes.Add(destination);
if (this_result > overall_result)
{
overall_result = this_result;
}
}
return overall_result;
}
目的是让此 "subtask" 根据循环中已处理的工作表数量报告进度。为此计算百分比是一项微不足道的任务,但我不清楚如何将其报告回 import_begin
方法。当这个"subtask"完成后,总体任务完成度(从import_begin
方法的POV)应该是25%。其他任务也类似。如何实现?
import_begin
其实不需要获取更新,直接调用子任务即可,而也传递了BackgroundWorker
,所以子任务负责直接报告他们的进展。如果 "polluting" 带有 BackgroundWorker
的子任务不可接受,则创建一个委托来调用 BackgroundWorker,这样您的子任务就会调用委托。
private void mainTask(object sender, DoWorkEventArgs e)
{
var worker = (BackgroundWorker)sender;
var report = new Action<int>(i => worker.ReportProgress(i)); //the delegate
smallTask1Clean(report); //this one pass the delegate
smallTask2(worker); //this one directly call background worker
worker.ReportProgress(100);
}
void smallTask1Clean(Action<int> a)
{
for (int i = 0; i < 20; i++)
{
Thread.Sleep(500);
a(i);
}
}
void smallTask2(BackgroundWorker w)
{
for (int i = 0; i < 5; i++)
{
Thread.Sleep(1000);
w.ReportProgress(i*80/5+20);
}
}
您还可以将子任务隔离开来,使其不必知道它们在较大任务中的作用,在这种情况下,委托应采用两个变量,即子任务的当前内部进度和它需要处理的总项目。
private void mainTask(object sender, DoWorkEventArgs e)
{
var worker = (BackgroundWorker)sender;
var preTaskProgress = 0;
var currentTaskTotalPercentage = 0;
var smarterDelegate = new Action<int, int>((current, total) =>
{
worker.ReportProgress(preTaskProgress + (current *currentTaskTotalPercentage/total));
});
currentTaskTotalPercentage = 30; //the following task will in total progressed the main task for 30%
smallTaskClean(smarterDelegate);
preTaskProgress = currentTaskTotalPercentage; //upate the main the progress before starting the next task
currentTaskTotalPercentage = 70; //the following task will in total progressed the main task for 70%
smallTaskClean(smarterDelegate);
worker.ReportProgress(100);
}
void smallTaskClean(Action<int,int> a)
{
for (int i = 0; i < 5; i++)
{
Thread.Sleep(1500);
a(i,5);
}
}