C# 接口未更改-winforms
我有一个函数,当函数启动时,我想显示一些UI组件,然后开始工作,最后,我想从那里删除这些组件。问题是我在表单上看不到UI的变化 我这样做的功能是:C# 接口未更改-winforms,c#,winforms,user-interface,C#,Winforms,User Interface,我有一个函数,当函数启动时,我想显示一些UI组件,然后开始工作,最后,我想从那里删除这些组件。问题是我在表单上看不到UI的变化 我这样做的功能是: public void Processor() { // ------------- SETTING UI COMPONENTS lblProgress.Visible = true; progressBar.Visible = true; btnStop.Visible = true; // -----
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;
}
有人能帮忙吗。如果我做错了什么,请告诉我。作为Vimalan回答的补充:
Application.DoEvents()
强制在windows消息队列中泵送消息。这意味着任何挂起的UI更新请求都是通过Application.DoEvents()
调用的,因此这是一种蛮力方法。我建议通过删除需要花费时间来处理并在seprate线程上运行的代码块,使您的UI具有响应性。现在,需要时间的代码也在主线程上运行(UI也在主线程上运行)。我想说,这会扼杀主线程,难以消化;)
请尝试阅读以下异步编程模式以了解更多信息:
或者您可以使用后台工作程序:
请不要使用
.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;
});
}
您可以使用“Rx WinForms”来获得所有这些好处。@user2831683,我想您现在知道使用Application.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:原始代码中唯一的更改是零件
/。。。。需要时间的工作
,由任务取代我总共有1066个URL,每个URL需要大约6秒的处理器。在写入控件后,尝试使用Application.DoEvents()。@user2831683虽然您似乎喜欢下面的答案,但它并不像您想象的那么好。阅读此解决方案:使用任务,异步/等待。请不要使用.DoEvents()
。请参阅我对Vimalan答案的评论。是的,这是另一个很好的方法-但是我认为您需要显示进度条是如何更新的,因为任务中的代码需要封送回UI线程。@Enigmativity与前面讨论的一样。不需要额外的代码。如果OP不访问其工作块中的任何UI组件,我看不出有任何问题。任务的工作不会操纵UI组件。据我所知,任务的工作可能会使处理器忙,UI组件会因此进入块队列而不响应。@user2831683所有UI更新都由一个线程处理。如果您让它保持忙碌,您的界面将没有响应。这就是全部想法。@EZI-OP正在更新循环中的进度条。这需要在UI线程上完成。