2010-06-10 3 views
1

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

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

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

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

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

ответ

1

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

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

thread.SetApartmentState(ApartmentState.STA); 

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

+0

Настройка квартиры позволяет мне создавать компоненты WPF в фоновом потоке. Но мне нужно переместить их в поток графического интерфейса позже. Эта статья показала путь (http://www.nbdtech.com/Blog/archive/2007/08/01/Passing-Wpf-Objects-Between-Threads-With-Source-Code.aspx), но это было с FixedDocument, подход не работает с DocumentPage, поскольку в нем отсутствует конструктор по умолчанию. Есть ли способ использовать класс Freezable для перемещения DocumentPage в поток графического интерфейса? – Mizipzor

+0

Устранить предложение Freezable - DocumentPage не наследует от Freezable и содержит Visual, поэтому было бы трудно создать подклассу Freezable DocumentPage. В приведенном примере используется XamlReader и XamlWriter для перемещения объекта по потокам - возможно, вы могли бы использовать BinaryFormatter (или какой-либо другой метод сериализации) для сериализации DocumentPages для потока, а затем читать их обратно с другой стороны? –

+0

Глядя на BinaryFormatter, похоже, что подход похож на тот, который использует XamlWriter. Возможно, он работает лучше, я смотрю на него, спасибо. знак равно – Mizipzor

0

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

0

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

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

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

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

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

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

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

0

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

0

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

 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 для отображения информации о ходе работы.

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

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

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

Смежные вопросы