2010-03-04 74 views
36

在我的WPF應用程序中,我做了一些異步通信(與服務器)。在回調函數中,我最終從服務器的結果創建InkPresenter對象。這要求正在運行的線程是STA,顯然它現在不是。因此,我得到以下例外:如何在STA線程中運行某些東西?

無法在程序集[..]中定義'InkPresenter'的實例調用線程必須是STA,因爲許多UI組件都需要這個。

目前我異步函數調用是這樣的:

public void SearchForFooAsync(string searchString) 
{ 
    var caller = new Func<string, Foo>(_patientProxy.SearchForFoo); 
    caller.BeginInvoke(searchString, new AsyncCallback(SearchForFooCallbackMethod), null); 
} 

我怎樣才能使回調 - 這將做InkPresenter創建 - 是STA?或者在新的STA線程中調用XamlReader解析。

public void SearchForFooCallbackMethod(IAsyncResult ar) 
{ 
    var foo = GetFooFromAsyncResult(ar); 
    var inkPresenter = XamlReader.Parse(foo.Xaml) as InkPresenter; // <!-- Requires STA 
    [..] 
} 
+0

無論發生在方法之前的[STAThread]嗎?並不總是合適但很容易。也許它直到2011年纔出來?我從2011年起就沒有用過它,我記得... – ebyrob 2017-07-06 03:41:38

回答

52

可以啓動STA線程像這樣:

Thread thread = new Thread(MethodWhichRequiresSTA); 
    thread.SetApartmentState(ApartmentState.STA); //Set the thread to STA 
    thread.Start(); 
    thread.Join(); //Wait for the thread to end 

唯一的問題是,你的結果對象,必須沿某種方式傳遞。您可以使用一個私有字段,或者潛入沿參數傳遞到線程。在這裏,我將foo數據設置在專用字段中,並啓動STA線程以改變inkPresenter!

private var foo; 
public void SearchForFooCallbackMethod(IAsyncResult ar) 
{ 
    foo = GetFooFromAsyncResult(ar); 
    Thread thread = new Thread(ProcessInkPresenter); 
    thread.SetApartmentState(ApartmentState.STA); 
    thread.Start(); 
    thread.Join(); 
} 

private void ProcessInkPresenter() 
{ 
    var inkPresenter = XamlReader.Parse(foo.Xaml) as InkPresenter; 
} 

希望這有助於!

+0

看起來非常有幫助 - thx!將嘗試將此應用於我的代碼。 – stiank81 2010-03-04 09:43:47

+0

謝謝:)讓我知道它是否能解決問題。我們使用這種技術在服務器上生成Xaml控件的PNG圖像! – Arcturus 2010-03-04 10:16:29

+0

似乎可以解決這個問題,但只是遇到了另一個問題。 *嘆息* ..只要我在這裏工作,就會馬上被接受...... Thx! – stiank81 2010-03-04 10:38:56

3

它應該足以在UI線程上調用它。因此,使用BackgroundWorkerRunWorkerAsyncCompleted,然後可以創建inkPresenter。

+0

你說得對。問題在於回調沒有在UI線程上運行。 UI線程與STA一起運行,所以在UI線程上運行它應該爲我解決這個問題。 – stiank81 2010-03-04 09:47:48

11

您可以使用Dipatcher類在UI線程上執行方法調用。 Dispatcher提供靜態屬性CurrentDispatcher來獲取線程的調度程序。

如果您創建InkPresenter的類的對象是在UI線程上創建的,則CurrentDispatcher方法將返回UI線程的Dispatcher。

在分派器上,您可以調用BeginInvoke方法在線程上異步調用指定的委託。

+1

Dispatcher.Invoke或BeginInvoke是要走的路。比公認的解決方案簡單得多 – GameAlchemist 2013-06-09 16:39:59

1

這是一個黑客攻擊的一位,但我會用XTATestRunner所以您的代碼將是這樣的:

public void SearchForFooAsync(string searchString) 
    { 
     var caller = new Func<string, Foo>(_patientProxy.SearchForFoo); 
     caller.BeginInvoke(searchString, new AsyncCallback(SearchForFooCallbackMethod), null); 
    } 

    public void SearchForFooCallbackMethod(IAsyncResult ar) 
    { 

      var foo = GetFooFromAsyncResult(ar); 
InkPresenter inkPresenter; 
      new XTATestRunner().RunSTA(() => { 
         inkPresenter = XamlReader.Parse(foo.Xaml) as InkPresenter; 
        }); 
    } 

作爲獎金有可能趕在STA(或MTA)拋出的異常的線程是這樣的:

try{ 
new XTATestRunner().RunSTA(() => { 
         throw new InvalidOperationException(); 
        }); 
} 
catch(InvalidOperationException ex){ 
} 
相關問題