我的Windows窗体应用中的线程仍在冻结我的用户界面

时间:2017-07-26 17:33:52

标签: c# multithreading winforms

背景

目前正在处理我要求创建的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

1 个答案:

答案 0 :(得分:3)

我还会考虑asyncawait模式。在这篇文章中解释: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的少数几次之一,而应该更倾向于在几乎所有其他情况下返回TaskTask<T>