c#在线程期间从外部方法更新进度表
准备好了否决票,但我真的离与这个后台工作人员处理线程的细节还有一段距离,但我已经设法为我想要的东西找到了一个结构:c#在线程期间从外部方法更新进度表,c#,multithreading,C#,Multithreading,准备好了否决票,但我真的离与这个后台工作人员处理线程的细节还有一段距离,但我已经设法为我想要的东西找到了一个结构: public class cls1 { private FormProgress myProgForm = new FormProgress(); public BackgroundWorker worker = new BackgroundWorker(); // new instance of bkgworker
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
}
}
}
乱七八糟的,对吧?但它是有效的(我24小时来一直在努力寻找/学习这些东西,这是我第一次远程理解
我遇到的问题是,在job1
例程中,从我想调用的任何其他方法调用UPDATEME()方法-例如,实际上,这不仅仅是浪费时间的循环,而是以各种顺序调用大量其他方法的一组条件
我尝试将第二个方法插入到job1
中,并在第二个方法调用UPDATEME
中,但这不是线程安全的跨线程更新
我认为这可能与调用有关,但后来我也读到了一些关于MSDN BackgroundWorker的内容,它是另一种在没有调用的情况下允许线程安全的方法,然后我的头爆炸了,我的大脑掉了出来
如何在代码中的任何其他方法中始终引用我的ProgressForm.UPDATEME(“新进度消息”)
方法?
编辑:
例如,我会在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);
}
如何始终引用我的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()
,但不使用递归(不太容易混淆,但我们现在引入了重复代码):
对于那些“面向细节”的方法/变体(我使用的是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(); }
}
你熟悉
event
s吗?我想这就是你想要的。为什么你不能直接调用ReportProgress()
来自job1
方法中的其他方法?这与在此循环中调用它没有什么区别。ProgressChanged
事件处理程序仍会将更新发送到您的UI。也许您可以向我们展示您迄今为止扩展此当前示例的尝试。是和否,我对事件处理程序相当满意在旧的Excel VBA中,甚至在c#/vb.Net中为事件添加了一些处理程序,但当涉及到异步调用事件时,我是一个完全的处女,我正在边做边学!只是做得不太好:DI尝试调用行(发送方作为BackgroundWorker)。ReportProgress(I)
在另一个方法中,只使用工作者
作为发送者
位(将其移动到公共属性而不是方法内)但是它仍然说它不是跨线程安全的,我编辑它是为了显示调用更新事件的第二个方法,但我认为现在唯一可以继续的方法是始终在第一级方法(Job1
)上调用该更新。因此,任何嵌套方法都必须完全执行,返回报告,然后第1级将调用更新。这并不理想,而且我仍然不明白,如果线性/同步调用,为什么嵌套线程不能调用该方法,但哦,好吧!哇,我在MSDN页面上读到了这一点,我以为它适用于除BackgroundWorker之外的其他线程类型,我甚至开始键入类似的内容(但在Lamda表达式中可能会迷失方向)-我真的不明白如何从内部调用该方法来绕过该方法在1级线程之外调用的事实,但非常感谢为我添加了一行。尝试了它,它工作了!!!
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(); }
}
}
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(); }
}