WPF — диспетчер PushFrame()

Я пытаюсь вызвать Dispatcher.PushFrame() из нескольких разных потоков, но сталкиваюсь с ошибкой:

Необходимо создать DependencySource в том же потоке, что и DependencyObject.

Вот фрагмент кода:

_lockFrame = new DispatcherFrame(true);
Dispatcher.PushFrame(_lockFrame);

Когда я попытался:

Dispatcher.CurrentDispatcher.Invoke(
    DispatcherPriority.Normal,
    new Action(() => _lockFrame = new DispatcherFrame(true));
Dispatcher.PushFrame(_lockFrame);

Я получаю сообщение об ошибке:

Объекты должны создаваться одним и тем же потоком.

Каков подход к отправке нескольких кадров в Dispatcher из разных потоков?


person Tri Q Tran    schedule 19.04.2010    source источник


Ответы (2)


Каждый поток имеет свой собственный объект диспетчера, возвращаемый Dispatcher.CurrentDispatcher.

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

Пользовательский интерфейс WPF имеет «сходство с потоком» — доступ к пользовательскому интерфейсу может получить только поток, который его создает.

Обновление: не уверен, чего вы пытаетесь достичь. Но у меня сработал следующий фрагмент кода.

    private Dispatcher _dispatcher;
    private DispatcherFrame _lockFrame;
    public Window1()
    {
        InitializeComponent();

        _dispatcher = Dispatcher.CurrentDispatcher;

        // the other thread
        Thread t = new Thread(
            (ThreadStart)delegate
            {

                _dispatcher.Invoke(
                    (Action)delegate
                    {
                        var frame = CreateNewFrame();
                        Dispatcher.PushFrame(frame);
                    });
            });
        t.Start();
person Gishu    schedule 19.04.2010
comment
Я пробовал это, но продолжаю получать объекты, которые должны быть созданы тем же потоком. ошибка. - person Tri Q Tran; 19.04.2010
comment
@Tri Q: см. обновление. Не уверен, что вашу проблему можно решить с помощью другого подхода... приведенный выше код заставляет меня съеживаться. - person Gishu; 19.04.2010
comment
что находится в CreateNewFrame()? Это эквивалентно «новому DispatcherFrame (true);» - person Tri Q Tran; 20.04.2010
comment
@Tri В: Да. Извините за это... как бы пропустил это. - person Gishu; 21.04.2010

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

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

Иногда вам приходится обрабатывать сообщения, не возвращаясь из вашего метода в цикл диспетчера, хорошим примером для этого являются модальные диалоги, которые реагируют на пользовательский ввод (поэтому им необходимо обрабатывать сообщения), не прерывая поток управления метода, который их вызвал.

Это то, что делает PushFrame — он запускает цикл диспетчера внутри вашего кода.

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

Вызов PushFrame из другого потока не может работать, потому что ваш вызов происходит в неправильном потоке, сам PushFrame должен вызываться в том же потоке, которым управляет диспетчер, вы не можете вызывать его в другом потоке, потому что он пытается обработать сообщения потока в другом потоке.

Использование Invoke или BeginInvoke здесь также не имеет смысла, потому что делегат, переданный этим методам, вызывается только тогда, когда диспетчер обрабатывает сообщения, если диспетчер уже обрабатывает сообщения, нет необходимости вызывать PushFrame, чтобы заставить его обрабатывать сообщения.

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

person Nir    schedule 19.04.2010
comment
Спасибо, это хорошее объяснение! Проблема именно такая, как вы описали. Модальное диалоговое окно, ориентированное на многопотоковое исполнение. Итак, как мне использовать одно (1) единственное модальное диалоговое окно для обработки запроса Show() из нескольких потоков? - person Tri Q Tran; 19.04.2010
comment
Вам нужен модальный диалог, который будет блокировать несколько потоков, пока не закроется? - person Nir; 19.04.2010
comment
Да, это то, что я ищу. Многопоточный модальный диалог. - person Tri Q Tran; 20.04.2010