Создание компонентов WPF в фоновом потоке - PullRequest
1 голос
/ 11 июня 2010

Я работаю над системой отчетности, серия DocumentPage должна быть создана через DocumentPaginator.Эти документы включают в себя ряд компонентов WPF , которые должны быть созданы, чтобы в paginator были правильные данные при последующей отправке на XpsDocumentWriter (который, в свою очередь, отправляется на реальный принтер).

Моя проблема сейчас заключается в том, что экземплярам DocumentPage требуется много времени для создания (достаточно, чтобы Windows пометила приложение как замороженное), поэтому я попытался создать их в фоновом потоке , что проблематично, посколькуWPF ожидает, что атрибуты для них будут установлены из потока GUI.Я также хотел бы, чтобы отображался индикатор выполнения, показывающий, сколько страниц было создано до сих пор.Таким образом, похоже, что я пытаюсь заставить две вещи происходить параллельно в графическом интерфейсе.

Проблема трудна для объяснения, и я действительно не уверен, как ее решить.Вкратце:

  • Создайте серию DocumentPag е.
    • К ним относятся компоненты WPF
    • Они должны быть созданы в фоновом потоке или использованы другие приемы, чтобы приложение не зависало.
  • После создания каждой страницы необходимо обновить WPF ProgressBar .

Если приличного способа сделать это, альтернативных решений и подходов больше, чемприветствуется.

Ответы [ 5 ]

1 голос
/ 11 июня 2010

Вы должны иметь возможность запускать paginator в фоновом потоке, если он является STA.

После того, как вы настроили свой поток, попробуйте выполнить его до запуска.

thread.SetApartmentState(ApartmentState.STA);

Если вы действительно должны быть в потоке графического интерфейса, то проверьте класс Freezable , так как вам, возможно, придется переместить объекты из фонового потока в поток графического интерфейса.

0 голосов
/ 09 декабря 2013

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

        Thread t = new Thread(() =>
            {
                ProgressDialog pd = new ProgressDialog(context);
                pd.WindowStartupLocation = System.Windows.WindowStartupLocation.CenterScreen;
                pd.Show();
                System.Windows.Threading.Dispatcher.Run();
            });
        t.SetApartmentState(ApartmentState.STA);
        t.IsBackground = true;
        t.Start();

        Action();   //we need to execute the action on the main thread so that UI elements created by the action can later be displayed in the main UI

ProgressDialog - это мое собственное окно WPF для отображения информации о прогрессе.

'context' содержит данные о прогрессе для моего диалога прогресса. Он включает отмененное свойство, поэтому я могу прервать действие, выполняемое в главном потоке. Он также содержит свойство complete, поэтому диалоговое окно хода выполнения может закрываться после завершения действия.

«Действие» - это метод, используемый для создания всех элементов пользовательского интерфейса. Он контролирует контекст для флага отмены и прекращает генерирование элементов пользовательского интерфейса, если флаг установлен. Он устанавливает полный флаг, когда это сделано.

Я не помню точную причину, по которой мне пришлось установить Thread 't' для потока STA и IsBackground в true, но я почти уверен, что без них это не сработает.

0 голосов
/ 06 августа 2010

Дальнейшая разработка ответа Рэя Бернса: не могли бы вы обработать данные в классе в фоновом потоке и затем привязать свойства DocumentPage к этому классу после завершения обработки?

0 голосов
/ 12 июня 2010

Я предполагаю, что все, что требует много времени для создания, находится внутри вашего Visual.Если это так, то существует простое решение: не создавайте фактические объекты DocumentPage и связанные с ними визуалы, пока не будет вызван DocumentPaginator.GetPage ().

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

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

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

  1. Представление миниатюры связывало бы свой ItemsSource с коллекцией "RealizedPages", которая изначально заполнена фиктивными страницами
  2. Всякий раз, когда фиктивная страница измеряется, онаставит в очередь диспетчерскую операцию в DispatcherPriority.Background, чтобы вызвать DocumentPaginator.GetPage (), а затем заменить фиктивную страницу в коллекции RealizedPages реальной страницей.

Если существуют проблемы с производительностью даже при реализации одной страницыиз-за количества отдельных элементов этот общий подход можно использовать в пределах независимо от того, что ItemsControl на странице содержит большое количество элементов.

Еще одно примечание: система печати XPS не 'никогда не обрабатывать более одной DocumentPage одновременно, поэтому, если вы знаете, что это ваш клиент, вы можете просто продолжать возвращать одну и ту же DocumentPage снова и снова с соответствующими изменениями.

0 голосов
/ 11 июня 2010

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

...