2017-07-29 65 views
0

我得到一個名爲Connect()的函數,因爲它使用了一些API請求,所以這個函數需要大約2-3秒。現在我想找到一種方式,當我開始使用這個功能時,我的Ui不會凍結。C#Ui在調用方法時會凍結

private void connectToolStripMenuItem_Click(object sender, EventArgs e) 
    { 
     Connect() // << this tooks a lot of time 
    } 

我試圖與線程

private void connectToolStripMenuItem_Click(object sender, EventArgs e) 
    { 
     new Thread(Connect).Start(); 
    } 

和backgroudnworker

private void backgroundWorkerConnect_DoWork(object sender, DoWorkEventArgs e) 
    { 
     Connect(); 
    } 

但仍PROGRAMM凍結來解決它。

private void Connect() 
    { 
     if (InvokeRequired) 
     { 
      Invoke(new MethodInvoker(Connect)); 
     } 
     else 
     { 
      if (!connected) 
      { 
       connected = true; 
       verbindenToolStripMenuItem.Enabled = false; 
       trennenToolStripMenuItem.Enabled = true; 
       InfoStripStatus.Text = "Status: Connected"; 

       irc.joinRoom(channel, BotConnectingMessage); 
       chatThread = new Thread(getMessage); 
       chatThread.Start(); 
       loadLoyalty(); 
       updateTimer = new System.Threading.Timer(timerViewer, null, 0, 60000); 
      } 
     } 
    } 

也許我只是做錯了事,希望有人能幫助我。

+0

開始一個新的線程不應該凍結UI,因爲它有它自己的線程 –

+0

而'連接();'方法不依賴或調用UI線程上的任何東西?如果你用'System.Threading.Thread.Sleep(3000)'替換'Connect()'中的任何東西;'它是否仍然凍結UI? (用最後兩個選項對它進行測試) – rene

+0

好吧,我試着用Connect()內容替換睡眠(3000),現在沒有更多的凍結。但我不明白爲什麼,因爲在連接()函數是沒有什麼需要那麼久。我在頂部添加Connect()的內容:) –

回答

2

使用另一個線程(無論是通過BackgroundWorker或者直接創建一個)來調用,它無非就是調用一些代碼回到UI線程,然後等待它的方法,是要解決什麼。你關心的代碼仍然在UI線程中執行,阻止它。

您應該使用async/awaitTask.Run()處理工作:

private async void connectToolStripMenuItem_Click(object sender, EventArgs e) 
{ 
    await Connect(); 
} 

private async Task Connect() 
{ 
    if (!connected) 
    { 
     connected = true; 
     verbindenToolStripMenuItem.Enabled = false; 
     trennenToolStripMenuItem.Enabled = true; 
     InfoStripStatus.Text = "Status: Connected"; 

     await Task.Run(() => irc.joinRoom(channel, BotConnectingMessage)); 
     chatThread = new Thread(getMessage); 
     chatThread.Start(); 
     loadLoyalty(); 
     updateTimer = new System.Threading.Timer(timerViewer, null, 0, 60000); 
    } 
} 

根據loadLoyalty()多麼慢的,你可能也想await Task.Run(loadLoyalty);,而不僅僅是直接調用它。

以上將執行它所屬的UI線程中的所有代碼,除了您通過Task.Run()調用的代碼

還有其他的方法,該代碼可以重構,包括與BackgroundWorker工程(即只使用Control.Invoke()首先要做的四項聲明,並直接運行在Connect()方法的其餘部分)的替代品。但恕我直言,上述使用async/await是今天的最佳選擇。

+0

Thx隊友後讀了一下asyn/await和任務它只適用於幾個變化 –

0

好的,看起來interssting。我會嘗試將它傳遞給其他函數,因爲我發現它是凍結它的updateTimer。

private void timerViewer(object state) 
    { 
     irc.sendChatMessage("/mods"); 
     UpdateStream(); 
     UpdateChatters(); 
    } 

    private void UpdateStream() 
    { 
     if (InvokeRequired) 
     { 
      Invoke(new MethodInvoker(UpdateStream)); 
     } 
     else 
     { 
      StreamInformations = TwitchROClient.getStream(TwitchROClient.getIDbyUsername("xzaliax")); 

      if (StreamInformations.stream != null) 
      { 

       viewers = StreamInformations.stream.Viewers; 
       totalviews = StreamInformations.stream.channel.Views; 

       if (followers == 0) 
       { 
        followers = StreamInformations.stream.channel.Followers; 
       } 
       else 
       { 
        if (followers < StreamInformations.stream.channel.Followers) 
        { 
         newFollower(); 
        } 
        followers = StreamInformations.stream.channel.Followers; 
       } 


       InfoStripViewer.Text = "| " + string.Format(CultureInfo.InvariantCulture, "{0:N0}", viewers).Replace(',', '.') + " :Viewer"; 
       InfoStripFollower.Text = "| " + string.Format(CultureInfo.InvariantCulture, "{0:N0}", followers).Replace(',', '.') + " :Follower "; 
       InfoStripTotalViewer.Text = "| " + string.Format(CultureInfo.InvariantCulture, "{0:N0}", totalviews).Replace(',', '.') + " :Total Viewers"; 
       InfoStripStream.Text = "| Stream: Online"; 
      } 
      else 
      { 
       InfoStripViewer.Text = "| -- :Viewer"; 
       InfoStripFollower.Text = "| -- :Follower"; 
       InfoStripTotalViewer.Text = "| -- :Total Viewers"; 
       InfoStripStream.Text = "| Stream: Offline"; 
      } 
     } 
    } 
    private void UpdateChatters() 
    { 
     if (InvokeRequired) 
     { 
      Invoke(new MethodInvoker(UpdateChatters)); 
     } 
     else 
     { 
      ChannenlChatters = TwitchROClient.getChatters(channel); 
      lbViewer.Items.Clear(); 

      if (ChannenlChatters != null) 
      { 
       if (ChannenlChatters.AllChatters != null) 
       { 
        tbChat.Text += "Checking the viewer list..." + Environment.NewLine; 
        if (ChannenlChatters.AllChatters.Admins.Count >= 0) lbViewer.Items.Add("_____________Admins_____________"); 
        foreach (string admin in ChannenlChatters.AllChatters.Admins) 
        { 
         lbViewer.Items.Add(String.Format("{0,5}", admin)); 
        } 
        if (ChannenlChatters.AllChatters.Admins.Count >= 0) lbViewer.Items.Add(""); 

        if (ChannenlChatters.AllChatters.Staff.Count >= 0) lbViewer.Items.Add("_____________Stuff______________"); 
        foreach (string stuff in ChannenlChatters.AllChatters.Staff) 
        { 
         lbViewer.Items.Add(String.Format("{0,5}", stuff)); 
        } 
        if (ChannenlChatters.AllChatters.Staff.Count >= 0) lbViewer.Items.Add(""); 

        if (ChannenlChatters.AllChatters.GlobalMods.Count >= 0) lbViewer.Items.Add("___________Global Mods__________"); 
        foreach (string globalmods in ChannenlChatters.AllChatters.GlobalMods) 
        { 
         lbViewer.Items.Add(String.Format("{0,5}", globalmods)); 
        } 

        if (ChannenlChatters.AllChatters.GlobalMods.Count >= 0) lbViewer.Items.Add(""); 
        foreach (string globalMods in ChannenlChatters.AllChatters.GlobalMods) 
        { 
         lbViewer.Items.Add(String.Format("{0,5}", globalMods)); 
        } 

        if (ChannenlChatters.AllChatters.Moderators.Count >= 0) lbViewer.Items.Add("___________Moderators___________"); 
        foreach (string moderator in ChannenlChatters.AllChatters.Moderators) 
        { 
         lbViewer.Items.Add(String.Format("{0,5}", moderator)); 
        } 

        if (ChannenlChatters.AllChatters.Viewers.Count >= 0) lbViewer.Items.Add("____________Viewers_____________"); 
        foreach (string viewers in ChannenlChatters.AllChatters.Viewers) 
        { 
         lbViewer.Items.Add(String.Format("{0,5}", viewers)); 
        } 
       } 
      } 
     } 
    } 

,所以我會閱讀更多關於ascny並等待和測試有點

+0

你的計時器回調做同樣的事情你的點擊處理程序。它在UI線程上運行_everything_。當然,這會阻止UI線程在工作。如果沒有可靠地再現問題的好的[mcve],就不可能提供任何具體的建議,但基本解決方案仍然是一樣的:不要阻塞UI線程以進行長時間運行。你似乎在做I/O,所以可能已經有異步方法可以調用。如果沒有,你可以在'await Task.Run()'成語上回退,就像我在這裏發佈的答案一樣。 –

相關問題