背景
目前正在处理我要求创建的Windows窗体应用程序。我遇到了一个问题,当调用资源密集型进程时,UI会冻结。我目前正在使用线程,据我所知,它用于防止UI冻结并接管整个电脑。
问题
目前我正在使用线程来调用我的基类中的方法,即打开位于远程服务器上的文件。该方法具有大约30至45秒的延迟。我正在创建我的后台线程并调用它来启动。当被激活时调用如果触发,但是当它被触发时它不会等待我的线程完成基本上给我一个null异常。因此,经过一些挖掘后,我发现为了等待线程完成,你必须调用.Join()
。但是当调用Join时,它完全冻结了我的UI。因此,我的聪明才智试图创建一个解决方案并创建一个while循环,直到该线程不再存活并继续。然而,这也冻结了UI。我错过了什么吗?在MSDN Doc
代码示例
class BaseClass
{
public CWClient ClientFileContext(string clientFile, bool compress)
{
Client clientContext = null;
try
{
if (compress == true)
{
clientContext = appInstance.Clients.Open2(clientFile, superUser, passWord, OpenFlags.ofCompressed);
}
else
{
clientContext = appInstance.Clients.Open2(clientFile, superUser, passWord, OpenFlags.ofNone);
}
}
catch (Exception ex)
{
//TODO
}
return clientContext;
}
}
public partial class Form1 : Form
{
private void button1_Click(object sender, EventArgs e)
{
BaseClass wpSec = new BaseClass();
CWClient client = null;
Thread backgroundThread = new Thread(
new ThreadStart(() =>
{
client = wpSec.ClientFileContext(selectedFileFullPath, true);
}
));
backgroundThread.Start();
//backgroundThread.Join(); << Freezes the UI
var whyAreYouNotWorking = "Stop";
}
}
我尝试了
while (backgroundThread.IsAlive == true)
{
for (int n = 0; n < 100; n++)
{
Thread.Sleep(500);
progressBar1.BeginInvoke(new Action(() => progressBar1.Value = n));
}
}
// This also freezes the UI
答案 0 :(得分:3)
我还会考虑async
和await
模式。在这篇文章中解释:Using async await still freezes GUI
您的代码应与此类似(Baseclass不会更改):
public partial class Form1 : Form
{
private async void button1_Click(object sender, EventArgs e)
{
BaseClass wpSec = new BaseClass();
CWClient client = await Task.Run(() =>
{
return wpSec.ClientFileContext(selectedFileFullPath, true);
}
);
var whyAreYouNotWorking = "Stop";
}
}
这是背后的信息,但希望这给出了启动任务的基本思路,然后在async
方法中等待结果。如果你不需要你的BaseClass,那也可以在lambda中,只留下你真正想要的东西。
上面@Chris Dunaway的链接也很棒。 http://blog.stephencleary.com/2013/08/taskrun-vs-backgroundworker-round-3.html
编辑:正如@BradlyUffner所提到的,这也是您应该使用async void
的少数几次之一,而应该更倾向于在几乎所有其他情况下返回Task
或Task<T>
。