Отчет о ходе выполнения из потока COM/STA в поток пользовательского интерфейса WPF

Я работаю над приложением, которое печатает PDF-файлы с использованием COM и Acrobat SDK. Приложение написано на 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

Как мне сообщить о ходе работы моей WPF ViewModel в потоке STA, созданном таким образом?


person jle    schedule 05.11.2012    source источник


Ответы (1)


На самом деле нет, вам нужно сообщать о прогрессе не от, а до (уже существующего) потока STA, в котором работает пользовательский интерфейс.

Этого можно добиться с помощью BackgroundWorker функций (ReportProgress доставляется в потоке, который запустил BackgroundWorker -- это должен быть ваш поток пользовательского интерфейса), или с помощью потока пользовательского интерфейса Dispatcher (обычно с Dispatcher.BeginInvoke).


Изменить:
В вашем случае решение с BackgroundWorker не сработает, так как его поток не является STA. Поэтому вам нужно работать с обычными DispatcherlInvoke:

// 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);
}

Если ваш текущий объект не имеет Dispatcher, вы можете взять его из своих объектов пользовательского интерфейса или модели представления (если вы ее используете).

person Vlad    schedule 05.11.2012
comment
Но компонент COM также должен работать в потоке STA, и я не хочу, чтобы он запускался в потоке пользовательского интерфейса, поскольку это занимает довольно много времени. - person jle; 06.11.2012
comment
@jle: Да, COM может работать в собственном потоке STA. Поток пользовательского интерфейса в любом случае также является STA. Если вы не можете использовать BackgroundWorker (поскольку его рабочий поток не является STA), вы можете сообщить о прогрессе только с помощью Dispatcher.BeginInvoke. - person Vlad; 06.11.2012
comment
Итак, вот что: dotnetventures.wordpress.com/2011/07/30/, который показывает, как это сделать, но я не понимаю, зачем мне это делать, если я могу просто создать поток с помощью диспетчера? - person jle; 06.11.2012
comment
Это победа - теперь это имеет смысл. - person jle; 06.11.2012
comment
@jle: действительно, дополнительный поток, как в упомянутой вами статье, на самом деле не нужен. - person Vlad; 06.11.2012