2009-06-17 109 views
3

我有一個WPF dll,其中包含許多Window類,並公開顯示這些窗口的方法。從WinForms創建WPF窗口BackgroundWorker

我還有一個單獨的WinForms項目,它調用BackgroundWorker組件的DoWork方法內的WPF項目中的其中一個方法。

上的代碼實例化一個WPF窗口行了,我得到以下運行時錯誤:

The calling thread must be STA, because many UI components require this.

谷歌搜索讓我this discussion。 (原來全碟答案在另外其他網站的問題堆棧溢出!)他掛this article,其中規定

The BackgroundWorker component works well with WPF ...

這篇文章還提到使用DispatcherObject的類,但我不明白如何使工作,我寧願繼續使用我的BackgroundWorker組件。

作爲一個測試案例,我想出了以下代碼來重現錯誤。在WPF類庫,這裏是在Window1.xaml.vb

代碼
Partial Public Class Window1 

    Public Shared Function ShowMe() As Boolean? 
     Dim w = New Window1 'Error appears on this line. 
     Return w.ShowDialog() 
    End Function 

End Class 

在WinForms應用程序,這裏是在Form1.vb的

Imports System.ComponentModel 

Public Class Form1 

    Private WithEvents worker As BackgroundWorker 
    Private Sub doWord(ByVal sender As Object, ByVal e As DoWorkEventArgs) Handles worker.DoWork 
     WpfLibrary.Window1.ShowMe() 
    End Sub 
    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click 
     worker = New BackgroundWorker 
     worker.RunWorkerAsync() 
    End Sub 
End Class 

碼即使當BackgroundWorker組件放置在Window1.xaml.vb本身中,會發生相同的錯誤。那麼,那篇文章是錯誤的,我不能真正使用WPF的BackgroundWorker?或者還有什麼我需要做的才能讓它起作用?

如果BackgroundWorker無法正常工作,那麼我將如何替換上面的Form1.vb中的代碼來使用Dispatcher?

回答

4

可以使用WPF的後臺工作,這不是你的問題。

你的問題是,你不能執行任何任務,在Winform或WPF應用程序的主UI線程外部更新UI,並且BackgroundWorker的DoWork方法正在另一個線程中運行。

因此,您必須在啓動BackgroundWorker或其RunWorkerCompleted事件之前,在BackgroundWorker的後臺線程之外打開新窗口。

不知道圍繞呼叫打開窗口的代碼,我很難進一步提出建議,但我希望這一點能讓您朝正確的方向發展。

+0

謝謝!我只是將DoWork事件中的代碼複製到RunWorkerCompleted事件中,並且它可以工作。 – CoderDennis 2009-06-17 18:22:37

+0

僅供參考,我認爲RunWorkerCompleted在啓動worker的同一線程上運行(而不是工作線程)。如果是這樣,您可能完全不使用BackgroundWorker。 – 2009-06-17 18:26:53

3

您的工作人員也可以創建自己的線程,將該線程標記爲STA,然後調用Thread.Join()等待它終止。然後,您可以在新線程上創建並顯示窗口(但請注意,如果不使用分派器,其他線程將無法與其交互)。

實例C#:

Thread workerThread = new Thread(ShowMyWindow); 
workerThread.SetApartmentState(ApartmentState.STA); 
workerThread.Start(); 
workerThread.Join(); 

然後:

private void ShowMyWindow() 
{ 
    WpfLibrary.Window1.ShowMe() 
}