C# 报告从COM/STA线程到WPF UI线程的进度

C# 报告从COM/STA线程到WPF UI线程的进度,c#,wpf,com,sta,acrobat-sdk,C#,Wpf,Com,Sta,Acrobat Sdk,我正在开发一个使用COM和AcrobatSDK打印PDF的应用程序。这个应用程序是用C#,WPF编写的,我正试图找出如何在一个单独的线程上正确运行打印。我已经看到BackgroundWorker使用线程池,因此不能设置为STA。我知道如何创建STA线程,但不确定如何从STA线程报告进度: Thread thread = new Thread(PrintMethod); thread.SetApartmentState(ApartmentState.STA); //Set the thread t

我正在开发一个使用COM和AcrobatSDK打印PDF的应用程序。这个应用程序是用C#,WPF编写的,我正试图找出如何在一个单独的线程上正确运行打印。我已经看到BackgroundWorker使用线程池,因此不能设置为STA。我知道如何创建STA线程,但不确定如何从STA线程报告进度:

Thread thread = new Thread(PrintMethod);
thread.SetApartmentState(ApartmentState.STA); //Set the thread to STA
thread.Start(); 
thread.Join(); //Wait for the thread to end

如何在这样创建的STA线程中向WPF ViewModel报告进度?

实际上不是,您需要将进度从报告到,而不是从报告到运行UI的(现有)STA线程

您可以通过
BackgroundWorker
函数(在启动
BackgroundWorker
的线程上交付——这应该是您的UI线程)或使用UI线程的
Dispatcher
(通常使用
Dispatcher.BeginInvoke
)来实现这一点


编辑:
对于您的情况,使用
BackgroundWorker
的解决方案将不起作用,因为它的线程不是STA。因此,您只需要使用普通的
DispatcherInvoke

// in UI thread:
Thread thread = new Thread(PrintMethod);
thread.SetApartmentState(ApartmentState.STA); //Set the thread to STA
thread.Start();

void PrintMethod() // runs in print thread
{
    // do something
    ReportProgress(0.5);
    // do something more
    ReportProgress(1.0);
}

void ReportProgress(double p) // runs in print thread
{
    var d = this.Dispatcher;
    d.BeginInvoke((Action)(() =>
            {
                SetProgressValue(p);
            }));
}

void SetProgressValue(double p) // runs in UI thread
{
    label.Content = string.Format("{0}% ready", p * 100.0);
}

如果当前对象没有调度程序,您可以从UI对象或视图模型(如果使用)获取调度程序。

实际上没有,您需要报告进程,而不是从而是运行UI的(已存在)STA线程

您可以通过
BackgroundWorker
函数(在启动
BackgroundWorker
的线程上交付——这应该是您的UI线程)或使用UI线程的
Dispatcher
(通常使用
Dispatcher.BeginInvoke
)来实现这一点


编辑:
对于您的情况,使用
BackgroundWorker
的解决方案将不起作用,因为它的线程不是STA。因此,您只需要使用普通的
DispatcherInvoke

// in UI thread:
Thread thread = new Thread(PrintMethod);
thread.SetApartmentState(ApartmentState.STA); //Set the thread to STA
thread.Start();

void PrintMethod() // runs in print thread
{
    // do something
    ReportProgress(0.5);
    // do something more
    ReportProgress(1.0);
}

void ReportProgress(double p) // runs in print thread
{
    var d = this.Dispatcher;
    d.BeginInvoke((Action)(() =>
            {
                SetProgressValue(p);
            }));
}

void SetProgressValue(double p) // runs in UI thread
{
    label.Content = string.Format("{0}% ready", p * 100.0);
}

如果您当前的对象没有调度程序,您可以从UI对象或视图模型(如果您使用的话)获取它。

但是COM组件也需要在STA线程中运行,我不希望它在UI线程中运行,因为它需要很长时间。@jle:是的,COM可以在自己的STA线程中运行。UI线程无论如何也是STA。如果您不能使用
BackgroundWorker
(因为它的工作线程不是STA),您可以只使用
Dispatcher.BeginInvoke
报告进度。下面是:,它说明了如何执行此操作,但我不明白当我可以使用Dispatcher创建线程时为什么要这样做?这是一个胜利——现在有意义了。@jle:的确,您提到的文章中所述的额外线程实际上并不需要。但是COM组件也需要在STA线程中运行,我不希望它在UI线程中运行,因为这需要很长时间。@jle:是的,COM可以在自己的STA线程中运行。UI线程无论如何也是STA。如果您不能使用
BackgroundWorker
(因为它的工作线程不是STA),您可以只使用
Dispatcher.BeginInvoke
报告进度。下面是:,它说明了如何执行此操作,但我不明白当我可以使用Dispatcher创建线程时为什么要这样做?这是一个胜利——现在有意义了。@jle:的确,像你提到的文章中那样的额外线程实际上并不需要。