从 WinForms BackgroundWorker 创建 WPF 窗口

发布于 2024-07-24 08:57:48 字数 1612 浏览 4 评论 0原文

我有一个 WPF dll,其中包含许多 Window 类并公开显示这些窗口的方法。

我还有一个单独的 WinForms 项目,该项目在 BackgroundWorker 组件的 DoWork 方法内调用 WPF 项目中的这些方法之一。

在实例化 WPF 窗口的代码行中,我收到以下运行时错误:

调用线程必须是 STA,因为许多 UI 组件都需要它。

通过 Google 搜索,我可以此讨论。 (事实证明,Jon Skeet 除了 Stack Overflow 之外还在其他网站上回答了问题!)他链接到

BackgroundWorker 组件与 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?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

秋风の叶未落 2024-07-31 08:57:49

您的工作线程还可以创建自己的线程,将该线程标记为 STA,然后调用 Thread.Join() 等待其终止。 然后,您将能够在新线程上创建并显示窗口(但请注意,如果不使用调度程序,其他线程将无法与其交互)。

C# 中的示例:

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

然后:

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

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()
}
深海蓝天 2024-07-31 08:57:48

可以在 WPF 中使用后台工作程序,这不是您的问题。

您的问题是,您无法在 winform 或 WPF 应用程序中执行从主 UI 线程外部更新 UI 的任何任务,并且 BackgroundWorker 的 DoWork 方法正在不同的线程中运行。

因此,您必须在启动BackgroundWorker 之前或在其RunWorkerCompleted 事件中在BackgroundWorker 的后台线程之外打开新窗口。

如果不知道打开窗口的调用周围的代码,我很难提供进一步的建议,但我希望这能为您指明正确的方向。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文