Создание окна WPF из WinForms BackgroundWorker - PullRequest
3 голосов
/ 17 июня 2009

У меня есть WPF dll, которая содержит несколько классов Window и предоставляет методы, которые отображают эти окна.

У меня также есть отдельный проект WinForms, который вызывает один из этих методов в проекте WPF внутри метода DoWork компонента BackgroundWorker.

В строке кода, которая создает экземпляр окна WPF, я получаю следующую ошибку времени выполнения:

Вызывающий поток должен быть STA, потому что это требуется для многих компонентов пользовательского интерфейса.

Поиск в Google позволил мне это обсуждение . (Оказывается, Джон Скит отвечает на вопросы на других сайтах, помимо переполнения стека!)

Компонент 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, возникает та же ошибка. Итак, эта статья неправильна, и я не могу использовать BackgroundWorker с WPF? Или мне нужно что-то еще сделать, чтобы заставить его работать?

Если BackgroundWorker не будет работать, то как мне заменить код в Form1.vb выше, чтобы вместо него использовать Dispatcher?

Ответы [ 2 ]

4 голосов
/ 17 июня 2009

Вы можете использовать фоновый рабочий с WPF, это не ваша проблема.

Ваша проблема в том, что вы не можете выполнить любую задачу, которая обновляет интерфейс извне основного потока пользовательского интерфейса в приложении winform или WPF, а метод DoWork BackgroundWorker's выполняется в другом потоке.

Поэтому вы должны открыть новое окно вне фонового потока BackgroundWorker, либо перед запуском BackgroundWorker, либо в его событии RunWorkerCompleted.

Не зная кода, который окружает вызов, чтобы открыть окно, мне трудно дать дальнейшие рекомендации, но я надеюсь, что это указывает вам правильное направление.

3 голосов
/ 17 июня 2009

Ваш работник также может создать свой собственный поток, пометить этот поток как STA, а затем вызвать Thread.Join(), чтобы дождаться его завершения. После этого вы сможете создать и показать окно в вашем новом потоке (хотя учтите, что никакой другой поток не сможет взаимодействовать с ним без использования Dispatcher).

Пример на C #:

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

А потом:

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