2017-09-02 72 views
0

我目前正在使用兩種形式和一個托盤圖標進行項目。但是,在顯示第二個窗體Form2時,我遇到了麻煩,它在以特定方式顯示後大約30秒鐘凍結。C# - 大約30秒後凍結窗體 - 多線程

第一種形式(Form1)始終顯示在背景中,只有兩個薄紅色按鈕覆蓋用戶顯示器兩側約7個像素,並且兩者之間的空間是透明的。這些按鈕用於在警報關閉時閃爍,並且它們可以成功使用下面的代碼。

運行此任務後,將創建一個新的Form2。 Form2顯示關於正在發生的警報的信息並允許確認,這也可以阻止紅色條閃爍。 Form1是在Form1的不透明度任務運行之後創建的。下面的代碼是在Program.cs的主要功能

 redBarForms = new List<Form1>(); 
     foreach (var screen in Screen.AllScreens) 
     { 
      var form = new Form1(); 
      form.Opacity = 0d; 
      form.Show(); 

      form.WindowState = FormWindowState.Normal; 
      form.Location = screen.WorkingArea.Location; 
      form.WindowState = FormWindowState.Maximized; 

      redBarForms.Add(form); // Only one is added right now, working from one screen 
     } 

     // Begin the loop which checks to see if the bars should be flashing. 
     Task.Run(() => 
     { 
      while (true) 
      { 
       while (flashingAlertBars) 
       { 
        for (int i = 1; i <= 100; i++) 
        { 
         foreach (var form in redBarForms) 
         { 
          form.Invoke(new Action(() => 
          { 
           form.Opacity = i/100d; 
          })); 
          i += 9; 
         } 
         Thread.Sleep(50); 
        } 

        for (int i = 100; i >= 1; i--) 
        { 
         foreach (var form in redBarForms) 
         { 
          form.Invoke(new Action(() => 
          { 
           form.Opacity = i/100d; 
          })); 
          i -= 9; 
         } 
         Thread.Sleep(50); 
        } 
       } 
      } 
     }); 

     MainForm = new Form2(); 

     // Start the updater on a background worker so that it doesn't 
      affect the UI thread 
     BackgroundWorker bgUpdater = new BackgroundWorker(); 
     bgUpdater.WorkerSupportsCancellation = true; 
     bgUpdater.DoWork += Updater_BGWorker_DoWork; 
     bgUpdater.RunWorkerAsync(); 

     // Start Form1 
     if (!redBarForms[0].IsDisposed) 
     { 
      redBarForms[0].Invoke(new Action(() => 
      { 
       Application.Run(redBarForms[0]); 
      })); 
     } 

創建兩種形式後,我有一個類,更新程序,即在一個BackgroundWorker(bgUpdater),用於獲取該警報的列表運行每隔10秒從Web API上下載一次,然後使該成員在其類中公開。 Form2有一個BackgroundWorker本身,然後在另一個10秒的時間間隔內從更新器中拉取該成員,並使用它創建可點擊的標籤並顯示其形式中每個當前報警的信息。

更新程序具有一項功能,用於在檢測到警報時發送Toast通知,並具有一個按鈕以將Form2打開到可以發送確認的正確頁面。該Toast通知按鈕的單擊事件運行下面的方法來打開窗體到正確的頁面:

static public void ShowManagementUI(Result monitor) 
    { 
     if (Application.OpenForms.OfType<Form2>().Count() > 0) 
     { 
      if (MainForm.InvokeRequired) 
      { 
       MainForm.Invoke(new Action(() => 
       { 
        MainForm.ShowWithResult(monitor); //This just does an Activate() 
       })); 
      } 
     } 
     else 
     { 
      if (MainForm.IsDisposed) 
       MainForm = new Form2(); 
      MainForm.Show(); 
      MainForm.ShowWithResult(monitor); //This just does an Activate() 
     } 

    } 

如果只是正常打開表單顯示窗體2(Form2.Activate()),也沒有問題,形式不凍結,但是當使用ShowManagementUI(結果監視器)顯示窗體時,Form2會在10-30秒之間的任何地方凍結,但Form1會一直閃爍紅色條。它不會拋出任何異常,但我有一種感覺,它可能試圖在UI線程上調用操作,但由於某種原因它被鎖定。

我不能爲我的生活找到爲什麼它會這樣做。有沒有人有任何建議追蹤這樣的凍結?

+2

不使用的invoke(),因爲它可能會導致應用程序死鎖。使用BeginInvoke代替 – MickyD

+0

感謝您的建議!那麼最好使用BeginInvoke呢? 我用BeginInvoke()替換了Invoke()的所有實例,但問題仍然存在 –

回答

0

在不透明度增加for循環中調用Application.DoEvents以使UI線程有機會呈現更改。 50ms間隔也很小。嘗試更大的數字。

但是總體來說,這不是動畫是一個好主意:P

+0

感謝您的指點!我把Application.DoEvents()放在for循環中,就像你提到的那樣,但問題仍然存在。我也將間隔更改爲100毫秒,但發生了相同的結果。 你能澄清一下你對「這不是一個好主意」的意思嗎?你有沒有關於如何以更高效的方式做到這一點的建議? –