我有一个函数,当函数开始时,我想显示一些UI组件,然后开始工作,最后,我想从那里擦除这些组件。问题是我没有在表单上看到UI的变化。
我做这个的函数是:
public void Processor()
{
// ------------- SETTING UI COMPONENTS
lblProgress.Visible = true;
progressBar.Visible = true;
btnStop.Visible = true;
// ------------- WORKING
int counter = 0, percent = 0;
foreach (string url in Urls)
{
.... WORKING THAT TAKES TIME
counter += 1;
percent = ((counter * 100) / Urls.Count());
// ------------- MODIFYING UI COMPONENTS
// Modification doesn't appear on the form while running
lblProgress.Text = "Progress: " + (percent > 100 ? 100 : percent) + "%";
progressBar.Value = percent;
}
// ------------- SETTING UI COMPONENTS
lblProgress.Visible = false;
progressBar.Visible = false;
btnStop.Visible = false;
lblDone.Visible = true;
}
有人能帮我一下吗?如果我做错了什么,请告诉我。
@user2831683,我想你现在知道使用应用程序。DoEvents不太可取。下面是您可以使用的另一个替代方法:
async public void Processor() //see the "async" keyword
{
//SETTING UI COMPONENTS
foreach (string url in Urls)
{
await Task.Run(() =>
{
//.... WORKING THAT TAKES TIME
});
//MODIFYING UI COMPONENTS
}
}
虽然DoEvents
使你的代码看起来工作,你的UI仍然被你的工作大多数时间阻塞。这种方法将允许您的UI进行更多的平滑更新(例如,在移动窗口等时)
PS:原始代码中唯一的变化是//.... WORKING THAT TAKES TIME
部分,它被Task
作为Vimalan回应的补充:
Application.DoEvents()
强制在windows消息队列上抽吸消息。这意味着任何挂起的UI更新请求都是通过Application.DoEvents()
调用的,所以这是一个暴力方法。我建议通过删除需要时间处理的代码块并在单独的线程上运行它来使您的UI响应。现在,需要时间的代码也在主线程上运行(UI也在主线程上运行),我认为这会阻塞主线程,并且很难吞咽和消化它;)
尝试阅读下面的异步编程模式来了解更多:https://msdn.microsoft.com/en-us/library/jj152938 (v = vs.110) . aspx
或者你可以使用一个后台worker:https://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx
请不要使用.DoEvents()
。它可能导致代码中的各种重入性问题,并可能破坏第三方代码。实际上,它也可以破坏内置的Windows窗体代码,这取决于你在做什么。
我当然建议BackgroundWorker
作为解决这个问题的标准方法。
我是这样处理这个问题的:
public void Processor()
{
// ------------- SETTING UI COMPONENTS
lblProgress.Visible = true;
progressBar.Visible = true;
btnStop.Visible = true;
// ------------- WORKING
Urls
.ToObservable(Scheduler.Default) // Goes to background thread
.Do(url =>
{
/* .... WORKING THAT TAKES TIME */
})
.Select((url, counter) => counter * 100 / Urls.Count())
.DistinctUntilChanged()
.ObserveOn(this) // back to the UI thread
.Subscribe(
percent => // Done each change in percent
{
lblProgress.Text = "Progress: " + (percent > 100 ? 100 : percent) + "%";
progressBar.Value = percent;
},
() => // Done when finished processing
{
lblProgress.Visible = false;
progressBar.Visible = false;
btnStop.Visible = false;
lblDone.Visible = true;
});
}
你可以使用NuGet"Rx-WinForms"来获得所有这些优点。