Как я могу создать элементы управления в не основной теме?

1

В нашем приложении у нас есть возможность печатать отчеты. Для этих отчетов мы используем такие классы, как FlowDocument, Canvas и некоторые другие элементы управления, такие как ярлыки. Поскольку элементы управления должны создаваться только в основном потоке, приложения показывают окно уведомлений, и пользователь должен ждать. Отчет может содержать до 100 страниц, поэтому это может занять несколько минут. И пользователь не может ничего сделать с приложением.

Есть ли вообще выход из этой ситуации?

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

Есть ли способ передать право собственности на объект на другой поток? Особенно с пользовательскими интерфейсами, такими как Canvas? Как я уже говорил, я могу создать отчет в дополнительном потоке, но приложение отказывается отображать его. Элементы управления, не созданные/принадлежащие основному потоку, не отображаются.

  • 0
    Работа с документами такого размера требует лучшего решения, чем готовый базовый компонент. Это требует индивидуального решения. Не видя ваш код, трудно что-либо предложить ...
Теги:
multithreading
wpf
user-interface

2 ответа

2

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

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

Быстрый пример для асинхронного вызова (изменить BeginInvoke к Invoke для синхронизации, и играть с DispatcherPriority соответственно)

 Application.Current.Dispatcher.BeginInvoke(new Action(() =>
            {
                // Your control creation here
            }), DispatcherPriority.Background);

Раньше я работал над подобной проблемой: Global DockManager, динамическая обработка DockManager содержимого, мне пришлось создавать свои элементы управления из Диспетчера, чтобы иметь возможность фактически добавлять их в мой DockManager. Удостоверьтесь, что вы избегаете каких-либо условий гонки с этими вызовами, и вы должны быть в порядке

0

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

Чтобы создать новый поток с инициализированным диспетчером WPF, вы можете использовать следующий код:

public class DispatcherBuilder : IBuilder<Dispatcher>
{
    public Dispatcher Build()
    {
        Dispatcher dispatcher = null;
        var manualResetEvent = new ManualResetEvent(false);
        var thread = new Thread(() =>
            {
                dispatcher = Dispatcher.CurrentDispatcher;
                var synchronizationContext = new DispatcherSynchronizationContext(dispatcher);
                SynchronizationContext.SetSynchronizationContext(synchronizationContext);

                manualResetEvent.Set();
                Dispatcher.Run();
            });
        thread.Start();
        manualResetEvent.WaitOne();
        manualResetEvent.Dispose();
        return dispatcher;
    }
}

Ещё вопросы

Сообщество Overcoder
Наверх
Меню