Creating a WPF Window from a WinForms BackgroundWorker

谁说我不能喝 提交于 2019-12-10 18:45:43

问题


I have a WPF dll that contains a number of Window classes and exposes methods that display those windows.

I also have a separate WinForms project that is calling one of those methods in the WPF project inside the DoWork method of a BackgroundWorker component.

On the line of code that instantiates a WPF Window, I get the following runtime error:

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

A google search let me to this discussion. (Turns out Jon Skeet answers questions on other sites in addition to Stack Overflow!) He linked to this article, which states

The BackgroundWorker component works well with WPF ...

That article also mentions using the DispatcherObject class, but I don't understand how to make that work and I would rather just continue using my BackgroundWorker component.

As a test case, I came up with the following code to reproduce the error. In the WPF class library, here is the code in 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

In the WinForms application, here is the code in 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

Even when the BackgroundWorker component is placed in Window1.xaml.vb itself, the same error occurs. So, is that article wrong and I can't really use a BackgroundWorker with WPF? Or is there something else I need to do to get it to work?

If the BackgroundWorker won't work, then how would I replace the code in Form1.vb above to use a Dispatcher instead?


回答1:


You can use a background worker with WPF, that's not your problem.

Your problem is that you can't perform any task that updates the UI from outside of the main UI thread in either a winform or WPF application and the BackgroundWorker's DoWork method is running in a different thread.

Therefore you must open the new window outside of the BackgroundWorker's background thread, either before you start the BackgroundWorker, or in its RunWorkerCompleted event.

Without knowing the code that surrounds the call to open the window it is difficult for me to advise further, but I hope that points you in the right direction.




回答2:


Your worker could also create its own thread, mark that thread as STA, and then call Thread.Join() to wait for it to terminate. You would then be able to create and show the window on your new thread (although note that no other thread will be able to interact with it without using the Dispatcher).

Example in C#:

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

And then:

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


来源:https://stackoverflow.com/questions/1008696/creating-a-wpf-window-from-a-winforms-backgroundworker

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!