已经准备好进行投票表决,但是与这个背景工作人员之间我真的无法完全了解线程的来龙去脉,但是我已经设法为我想要的内容搭建了一个结构:
public class cls1
{
private FormProgress myProgForm = new FormProgress();
public BackgroundWorker worker = new BackgroundWorker(); // new instance of bkgworker
public void prepare_a_job()
{
worker.WorkerReportsProgress = true; // Allows the worker to report progress
worker.ProgressChanged += worker_ProgressChanged; // Adding handler to update progress
worker.DoWork += job1; // Adding handler for the ACTUAL JOB METHOD
myProgForm.Show(); // Show the prog update form
worker.RunWorkerAsync(); // Start the job, already! Wo lo loo
}
void job1(object sender, EventArgs e) // Do 0 to 100
{
for (int i = 0; i <= 100; i++)
{
(sender as BackgroundWorker).ReportProgress(i); // ReportProgress uses percentages
Thread.Sleep(50);
}
// THIS IS WHERE I'D INSERT ANOTHER METHOD
}
void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
if(e.ProgressPercentage == 100) // If the % gets to 100
{
myProgForm.UPDATEME("", true); // then pass true to close progressForm
}
else
{
myProgForm.UPDATEME("Counting\n" + e.ProgressPercentage); // else just update
}
}
}
在我的FormProgress
上我有以下方法:
public void UPDATEME(string MSG, bool finish = false)
{
this.label1.Text = MSG;
this.Refresh();
if (finish) { this.Close(); }
}
凌乱吧?但这确实有效(而且我24个小时一直在尝试查找/学习这些东西,这是我什至遥不可及的第一件事。
我遇到的问题是,在job1
例程中,我想从其他任何要调用的方法中调用UPDATEME()方法,例如实际上,这不只是浪费时间的循环,而是一系列条件,以各种顺序调用大量其他方法。
我尝试将第二种方法绑定到job1
中,并在该第二种方法调用UPDATEME
中进行捆绑,但这不是线程安全的跨线程更新...
我认为这可能与调用有关,但是随后我还阅读了有关MSDN BackgroundWorker的另一种信息,该方式允许线程安全而无需调用,然后我的脑袋爆炸了,我的大脑掉了下来。
如何在代码中的任何其他方法中始终引用我的ProgressForm.UPDATEME("new progress message")
方法?
编辑:
例如,我将在job1
调用中插入对此第二个方法的调用
void myOtherMethod()
{
(worker).ReportProgress(0);
myProgForm.UPDATEME("Doing part 1");
Thread.Sleep(1000);
myProgForm.UPDATEME("Doing part 2");
Thread.Sleep(1000);
myProgForm.UPDATEME("Doing part 3");
Thread.Sleep(1000);
}
答案 0 :(得分:1)
如何始终引用我的ProgressForm.UPDATEME(“新进度 message”)方法在我代码中的其他任何方法中?
赞:
public void UPDATEME(string MSG, bool finish = false)
{
if (this.InvokeRequired)
{
this.Invoke(new MethodInvoker(() => this.UPDATEME(MSG, finish)));
}
else
{
this.label1.Text = MSG;
if (finish) { this.Close(); }
}
}
我不太了解如何从内部调用该方法 解决方法在第一个级别之外被调用的事实 线程...
一开始它令人困惑,因为这是递归调用。 “肉”是Invoke()
在创建控件的同一线程(在这种情况下为表单本身)上运行其内部的内容。当我们第二次进入该方法时(由于递归),该检查返回false,并在UI线程上安全地运行else块。
您实际上可以通过始终调用Invoke()
来摆脱检查(和递归),就像这样:
public void UPDATEME(string MSG, bool finish = false)
{
this.Invoke(new Action(() =>
{
this.label1.Text = MSG;
if (finish) { this.Close(); }
}));
}
这是一个替代版本,它仍在检查是否需要Invoke()
,但不使用递归(减少混乱,但是我们现在引入了重复的代码):
public void UPDATEME(string MSG, bool finish = false)
{
if (this.InvokeRequired)
{
this.Invoke(new Action(() =>
{
this.label1.Text = MSG;
if (finish) { this.Close(); }
}));
}
else
{
this.label1.Text = MSG;
if (finish) { this.Close(); }
}
}
对于那些“注重细节”的人,这是一种方法/变体(我使用MethodInvoker
而不是Action
)显示了一种删除上面重复代码的方法:
public void UPDATEME(string MSG, bool finish = false)
{
if (this.InvokeRequired)
{
this.Invoke((MethodInvoker)delegate
{
this.updater(MSG, finish);
});
}
else
{
this.updater(MSG, finish);
}
}
private void updater(string MSG, bool finish = false) // NOT thread safe, thus the private (don't call directly)
{
this.label1.Text = MSG;
if (finish) { this.Close(); }
}