2012-08-31 30 views
1

所以我不知道如何提出這個問題,可能是我有問題找到答案的原因之一。使用COM對象鎖的UI的後臺工作仍然

所以我的設置是,我有一個類

public class Connection 
{ 
    public static event EventHandler LogggedIn; 
    public static TDConnection TDC {get;set;} 
    public string Authenticate(){...} 
    public static void Login() 
    { 
     if (Connection.TDC.Connected) 
     { 
      _bw = new BackgroundWorker 
      { 
       WorkerReportsProgress = true, 
       WorkerSupportsCancellation = true 
      }; 
      _bw.DoWork += ConnectToProject_DoWork; 
      _bw.RunWorkerCompleted += ConnectToProject_RunWorkerCompleted; 

      _bw.RunWorkerAsync(Connection.TDC); 
     } 
    } 

    private static void ConnectToProject_DoWork(object o, DoWorkEventArgs e) 
    { 
     Connection.TDC.ConnectProjectEx(Connection.Domain, Connection.Project, Connection.UserName, Utilities.Encryption.AESEncryption.Decrypt(Connection.Password, "fsd*#(dfs(((>>>???fdjs")); 
    } 

    private static void ConnectToProject_RunWorkerCompleted(object o, RunWorkerCompletedEventArgs e) 
    { 
     LogggedIn(null, new EventArgs()); 
    } 
} 

在我的主I類實例化一個新的連接,並調用登錄這將打開TDConnection到ALM一個新的連接。在我的線程中,我想在我的線程中使用這個已經打開的連接。從我讀過的內容來看,如果我這樣做,我的UI將會被阻塞,因爲我在UI線程上使用成員的方法,即使我在後臺工作者的內部。

一個解決方案,我發現這樣做:

private static void ConnectToProject_DoWork(object o, DoWorkEventArgs e) 
    { 
     TDConnection conn = new TDConnection(); 
     conn.InitConnectionEx(QCURL); 

     conn.Login(); 

     conn.ConnectProject(); 

     e.Result = conn; 
    } 

我不想這樣做,因爲我已經登錄,它需要額外的時間來做到這一點。

我已經嘗試過使用_bw.RunorkerAsync(Connection.TDC)傳遞Connection.TDC,但這顯然不起作用。

有什麼辦法可以使用已經建立的連接,而不是在連接時阻止UI?

+2

這裏沒有UI代碼。你是否從你的UI線程調用這個類的方法,直到後臺工作完成? – pstrjds

+1

您的WorkerReportsProgress和Cancellation設置具有誤導性(因爲未使用)。 –

+0

對不起。我正在使用Winform按鈕單擊事件處理程序中的Connection.Login。由於連接將在一個線程中打開,因此我建立了一個事件處理程序來觸發連接建立。因爲它是從我的Winform中調用的,所以它會阻止我的UI。 – Smeiff

回答

5

這在COM對象中很常見。就像.NET類一樣,許多COM類也不是線程安全的。在.NET中,如果您以線程不安全的方式使用.NET類,則可以拍攝自己的腳。不在COM中,它保證一個coclass宣稱自己不是線程安全的將以線程安全的方式使用。

它通過自動將來自工作線程的方法調用封送到創建對象的線程來完成。你可以看到它在哪裏,你在主線程上創建了TDC對象。所以當你從BackgroundWorker調用它的時候,仍然會在主線程上執行調用

解決此問題的唯一方法是在您使用它的同一個線程上創建對象。這通常也意味着您不能使用BackgroundWorker,您可能需要創建一個線程並調用其SetApartmentState()方法將其切換到STA。

+0

你知道我可以看一個很好的例子嗎?我沒有聽說過SetApartmentState,乍一看我沒有找到太多有用的文章。 – Smeiff

+1

http://stackoverflow.com/a/4271581/17034 –

+0

也許我失去了一些東西,但切換到STA線程意味着它仍然會阻止是不是?也許我不明白你的例子,但如果我在STA線程內調用Connecton.TDC.ConnectToProject,它仍然會阻止正確的? – Smeiff