Dot-Net

如何線上程中打開表單並強制它保持打開狀態

  • December 1, 2015

我仍然無法弄清楚如何在我在這裡討論的單獨的 UI 執行緒中創建 winforms 。

為了弄清楚這一點,我編寫了以下簡單的測試程序。我只是希望它在名為“UI 執行緒”的單獨執行緒上打開一個表單,並在表單打開時保持執行緒執行,同時允許使用者與表單互動(旋轉是作弊)。我理解為什麼下面會失敗並且執行緒會立即關閉,但我不確定我應該怎麼做才能修復它。

using System;
using System.Windows.Forms;
using System.Threading;

namespace UIThreadMarshalling {
   static class Program {
       [STAThread]
       static void Main() {
           Application.EnableVisualStyles();
           Application.SetCompatibleTextRenderingDefault(false);
           var tt = new ThreadTest();
           ThreadStart ts = new ThreadStart(tt.StartUiThread);
           Thread t = new Thread(ts);
           t.Name = "UI Thread";
           t.Start();
           Thread.Sleep(new TimeSpan(0, 0, 10));
       }

   }

   public class ThreadTest {
       Form _form;
       public ThreadTest() {
       }

       public void StartUiThread() {
           _form = new Form1();
           _form.Show();
       }
   }
}

在一個新執行緒上,呼叫 Application.Run 傳遞表單對象,這將使執行緒在視窗打開時執行自己的消息循環。

然後,您可以在該執行緒上呼叫 .Join 以使您的主執行緒等到 UI 執行緒終止,或者使用類似的技巧來等待該執行緒完成。

例子:

public void StartUiThread()
{
   using (Form1 _form = new Form1())
   {
       Application.Run(_form);
   }
}

我認為您的問題在於這個想法:“在名為’UI執行緒’的單獨執行緒上打開一個表單”

Windows 的工作方式是這樣的(請注意 Vista 可能會改變其中的一些現實):

有一個重要的執行緒稱為“主執行緒”或“ UI 執行緒”。該執行緒是處理Windows 消息的執行緒,例如“嘿,滑鼠點擊了這個像素”。

這些消息進入隊列,主執行緒在不忙於做其他事情時處理它們。

因此,如果你在主執行緒上呼叫 foo() 函式,如果需要很長時間,則在此期間不會處理任何 windows 消息,因此不會發生使用者互動。

主執行緒還在螢幕上繪製 UI,因此長時間執行的 foo() 也會阻止您的應用繪製。

除了這個神聖而特殊的主執行緒之外的所有其他執行緒都是 grunt 工作執行緒。這些工作執行緒可以做事,但它們永遠不能直接與使用者界面互動。

這種現實導致了兩個問題:

  1. 擺脫主執行緒:由於您不希望長時間執行的 foo() 停止所有使用者互動,因此您需要將該工作傳遞給工作執行緒。
  2. 回到主執行緒:當長時間執行的 foo() 完成時,您可能希望通過在 UI 中執行某些操作來通知使用者,但您不能在工作執行緒中執行此操作,因此您需要“返回”到主執行緒。

因此,我相信您在上述程序中的問題非常普遍:您的目標是不正確的,因為除了神聖的主執行緒之外,不應在任何執行緒中呼叫 _form.Show() 。

引用自:https://stackoverflow.com/questions/167323