在任务 运行 时以另一种形式更新进度条
Update progress bar in another form while task is running
**最终我将同时处理四个任务 运行ning 并有另一个包含四个进度条的表单。我希望每个进度条在其工作任务完成时进行更新。
这是我要为初学者做的事情。
我有一个表格,上面有一些按钮。当我点击一个时,我正在创建一个新任务来做一些工作。
public partial class MyMainForm : Form
{
private void btn_doWork_Click(object sender, EventArgs e)
{
Task task = new Task(RunComparisons);
task.Start();
}
private void RunComparisons()
{
int progressBarValue = 0;
MyProgressBarForm pBar = new MyProgressBarForm(maxValue, "some text");
pBar.ShowDialog();
foreach(string s in nodeCollection)
{
//do some work here
progressBarValue++;
pBar.updateProgressBar(progressBarValue, "some new text");
}
pBar.BeginInvoke(new Action(() => pBar.Close()));
}
}
在另一个包含带有进度条的表单的 class 中:
public partial class MyProgressBarForm : Form
{
public MyProgressBarForm(int maxValue, string textToDisplay)
{
InitializeComponent();
MyProgressBarControl.Maximum = maxValue;
myLabel.Text = textToDisplay;
}
public void updateProgressBar(int progress, string updatedTextToDisplay)
{
MyProgressBarForm.BeginInvoke(
new Action(() =>
{
MyProgressBarControl.Value = progress;
myLabel.Text = updatedTextToDisplay;
}));
}
当我单击 doWork 按钮时,进度条表单会显示但不会更新。它只是坐在那里挂着。如果我注释掉 pBar.ShowDialog();然后进度条表单不显示,但要完成的工作是 运行 完美完成。
当我创建自己的线程时,我已经完美地工作了,但我阅读了有关 Tasks 的内容,现在我正试图以这种方式实现它 运行。我哪里错了?
.ShowDialog
是阻塞调用;在对话框 returns 出现结果之前,执行不会继续。您可能应该查看 BackgroundWorker 来处理另一个线程上的工作并更新对话框。
在父窗体的主 UI 线程上创建进度条窗体,然后在按钮单击事件中调用对象的 Show()
方法。
这是一个包含 2 个柱的示例:
//In parent form ...
private MyProgressBarForm progressBarForm = new MyProgressBarForm();
private void button1_Click(object sender, EventArgs e)
{
progressBarForm.Show();
Task task = new Task(RunComparisons);
task.Start();
}
private void RunComparisons()
{
for (int i = 1; i < 100; i++)
{
System.Threading.Thread.Sleep(50);
progressBarForm.UpdateProgressBar(1, i);
}
}
//In MyProgressBarForm ...
public void UpdateProgressBar(int index, int value)
{
this.Invoke((MethodInvoker) delegate{
if (index == 1)
{
progressBar1.Value = value;
}
else
{
progressBar2.Value = value;
}
});
}
TPL 添加了 IProgress
接口,用于更新 UI 长 运行 非 UI 操作的进度。
您需要做的就是在您的 UI 中创建一个 Progress
实例,其中包含有关如何根据进度更新它的说明,然后将其传递给您的工作人员,工作人员可以通过它报告进度。
public partial class MyMainForm : System.Windows.Forms.Form
{
private async void btn_doWork_Click(object sender, EventArgs e)
{
MyProgressBarForm progressForm = new MyProgressBarForm();
progressForm.Show();
Progress<string> progress = new Progress<string>();
progress.ProgressChanged += (_, text) =>
progressForm.updateProgressBar(text);
await Task.Run(() => RunComparisons(progress));
progressForm.Close();
}
private void RunComparisons(IProgress<string> progress)
{
foreach (var s in nodeCollection)
{
Process(s);
progress.Report("hello world");
}
}
}
public partial class MyProgressBarForm : System.Windows.Forms.Form
{
public void updateProgressBar(string updatedTextToDisplay)
{
MyProgressBarControl.Value++;
myLabel.Text = updatedTextToDisplay;
}
}
这让 Progress Form 处理向 UI 显示进度,工作代码只处理工作,主窗体简单地创建进度窗体,开始工作,然后关闭窗体完成后,它将通过 UI 线程跟踪进度和编组的所有工作留给 Progress
。它还避免了多个 UI 线程;您当前从非 UI 线程创建和操作 UI 组件的方法会产生许多问题,使代码复杂化并使其更难维护。
**最终我将同时处理四个任务 运行ning 并有另一个包含四个进度条的表单。我希望每个进度条在其工作任务完成时进行更新。
这是我要为初学者做的事情。
我有一个表格,上面有一些按钮。当我点击一个时,我正在创建一个新任务来做一些工作。
public partial class MyMainForm : Form
{
private void btn_doWork_Click(object sender, EventArgs e)
{
Task task = new Task(RunComparisons);
task.Start();
}
private void RunComparisons()
{
int progressBarValue = 0;
MyProgressBarForm pBar = new MyProgressBarForm(maxValue, "some text");
pBar.ShowDialog();
foreach(string s in nodeCollection)
{
//do some work here
progressBarValue++;
pBar.updateProgressBar(progressBarValue, "some new text");
}
pBar.BeginInvoke(new Action(() => pBar.Close()));
}
}
在另一个包含带有进度条的表单的 class 中:
public partial class MyProgressBarForm : Form
{
public MyProgressBarForm(int maxValue, string textToDisplay)
{
InitializeComponent();
MyProgressBarControl.Maximum = maxValue;
myLabel.Text = textToDisplay;
}
public void updateProgressBar(int progress, string updatedTextToDisplay)
{
MyProgressBarForm.BeginInvoke(
new Action(() =>
{
MyProgressBarControl.Value = progress;
myLabel.Text = updatedTextToDisplay;
}));
}
当我单击 doWork 按钮时,进度条表单会显示但不会更新。它只是坐在那里挂着。如果我注释掉 pBar.ShowDialog();然后进度条表单不显示,但要完成的工作是 运行 完美完成。
当我创建自己的线程时,我已经完美地工作了,但我阅读了有关 Tasks 的内容,现在我正试图以这种方式实现它 运行。我哪里错了?
.ShowDialog
是阻塞调用;在对话框 returns 出现结果之前,执行不会继续。您可能应该查看 BackgroundWorker 来处理另一个线程上的工作并更新对话框。
在父窗体的主 UI 线程上创建进度条窗体,然后在按钮单击事件中调用对象的 Show()
方法。
这是一个包含 2 个柱的示例:
//In parent form ...
private MyProgressBarForm progressBarForm = new MyProgressBarForm();
private void button1_Click(object sender, EventArgs e)
{
progressBarForm.Show();
Task task = new Task(RunComparisons);
task.Start();
}
private void RunComparisons()
{
for (int i = 1; i < 100; i++)
{
System.Threading.Thread.Sleep(50);
progressBarForm.UpdateProgressBar(1, i);
}
}
//In MyProgressBarForm ...
public void UpdateProgressBar(int index, int value)
{
this.Invoke((MethodInvoker) delegate{
if (index == 1)
{
progressBar1.Value = value;
}
else
{
progressBar2.Value = value;
}
});
}
TPL 添加了 IProgress
接口,用于更新 UI 长 运行 非 UI 操作的进度。
您需要做的就是在您的 UI 中创建一个 Progress
实例,其中包含有关如何根据进度更新它的说明,然后将其传递给您的工作人员,工作人员可以通过它报告进度。
public partial class MyMainForm : System.Windows.Forms.Form
{
private async void btn_doWork_Click(object sender, EventArgs e)
{
MyProgressBarForm progressForm = new MyProgressBarForm();
progressForm.Show();
Progress<string> progress = new Progress<string>();
progress.ProgressChanged += (_, text) =>
progressForm.updateProgressBar(text);
await Task.Run(() => RunComparisons(progress));
progressForm.Close();
}
private void RunComparisons(IProgress<string> progress)
{
foreach (var s in nodeCollection)
{
Process(s);
progress.Report("hello world");
}
}
}
public partial class MyProgressBarForm : System.Windows.Forms.Form
{
public void updateProgressBar(string updatedTextToDisplay)
{
MyProgressBarControl.Value++;
myLabel.Text = updatedTextToDisplay;
}
}
这让 Progress Form 处理向 UI 显示进度,工作代码只处理工作,主窗体简单地创建进度窗体,开始工作,然后关闭窗体完成后,它将通过 UI 线程跟踪进度和编组的所有工作留给 Progress
。它还避免了多个 UI 线程;您当前从非 UI 线程创建和操作 UI 组件的方法会产生许多问题,使代码复杂化并使其更难维护。