我遇到了一个问题,我正在使用Backgroundworker在进度条中显示我的工作进度。用于背景工作者的代码: -
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
Thread.Sleep(200);
for (int i = 0; i <= 100; i++)
{
Delegate del= new DELEGATE(simulateHeavyWork);
this.Invoke(del);
backgroundWorker1.ReportProgress(i);
if (backgroundWorker1.CancellationPending)
{
e.Cancel = true;
backgroundWorker1.ReportProgress(0);
return;
}
}
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
percentLabel.Text = e.ProgressPercentage.ToString() + "%";
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled)
{
MessageBox.Show("Cancelled");
}
else
{
MessageBox.Show("Completed");
}
}
我在代码上创建了一个委托: -
public partial class Form1 : Form
{
private delegate void DELEGATE();
public Form1()
{
InitializeComponent();
}
private void simulateHeavyWork()
{
Thread.Sleep(100);
...lines of code to perform some search logs operation..
....
}
}
我想要实现的功能是进度条应该报告我的函数simulateHeavyWork()的进度,它实际上是使用UI线程,因为它需要从我的表单控件获取输入并更新它。
现在发生的问题是: - a)代码实际上是调用simulateHeavyWork()并给出更新ui控件和工作的输出。(注意:我在这里使用了委托来避免在ui线程上运行的错误交叉控件,因为我的函数需要使用UI控件。)
一旦完成,它就开始更新进度条,这是错误的,看起来它一次又一次地调用simulateHeavyWork,并且有睡眠间隙(100)。
请帮忙!!! 问候
答案 0 :(得分:1)
user3222101,正如Andy之前所说,你正在连续运行simulateHeavyWork()。此外,通过调用Invoke,您在UI线程中运行此方法,这会在UI线程中导致额外的睡眠。基本上,Invoke使用您使用它的控件的消息循环(泵)(在这种情况下为Form1)并将您的委托放入UI线程的队列以便执行。由于Sleep()调用以及simulateHeavyWork()方法中耗时的日志操作,我认为这不是一个好习惯。
我希望,明白你的问题。我建议将耗时的日志操作与UI线程分开。不要将缓慢而枯燥的I / O操作花费在UI线程的宝贵时间上。从控件中获取值(使用BackgroundWorker
中的Invoke,我将在下面解释),在BackgroundWorker
中执行任何操作并更新GUI(再次使用Invoke)而不触及此类UI线程沉重的任务。
正如Andy建议的那样,你可以通过RunWorkerAsync
的参数传递数据,你应该创建一个可以存储你需要的任何数据的类(因为它只接受一个参数)。但是,您可以通过使用Invoke从其他线程获取表单中的值。 Invoke
方法还会返回代理中的值(请参阅下面链接中的示例),这样您就有机会在窗体上获取控件的值。创建一个委托,该委托返回您为RunWorkerAsync
创建的类型类的对象,并在BackgroundWorker
线程中使用此值。请查看here中的示例。
public static string GetTextThreadSafe(this TextBox box)
{
return GetTextBoxText(box);
}
此外,示例使用Func<...>来返回值。
通过这种方式,您可以暂停(在BackgroundWorker
线程中)一段时间,然后从控件中获取值(当前值)并执行您想要的任何操作(再次在BackgroundWorker
线程中)。我认为,这可以改善您的代码。
答案 1 :(得分:0)
从您的问题:“这是错误的,看起来它一次又一次地调用simulateHeavyWork与睡眠的差距(100)。”
当然是打电话。看看你的代码:
for (int i = 0; i <= 100; i++)
{
Delegate del= new DELEGATE(simulateHeavyWork);
this.Invoke(del);
所以你在这里打电话simulateHeavyWork
100次。由于您在Thread.Sleep(100);
的正文中输入了simulateHeavyWork
,因此通话之间的差距约为Sleep(100)