C# 报告从COM/STA线程到WPF UI线程的进度
我正在开发一个使用COM和AcrobatSDK打印PDF的应用程序。这个应用程序是用C#,WPF编写的,我正试图找出如何在一个单独的线程上正确运行打印。我已经看到BackgroundWorker使用线程池,因此不能设置为STA。我知道如何创建STA线程,但不确定如何从STA线程报告进度: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
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:的确,像你提到的文章中那样的额外线程实际上并不需要。