2009-06-17 62 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() 
}