WPF - Диспетчер PushFrame () - PullRequest
       16

WPF - Диспетчер PushFrame ()

1 голос
/ 19 апреля 2010

Я пытаюсь вызвать 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);

Я получаю ошибку:

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

Каков подход к загрузке нескольких кадров в Диспетчер из разных потоков?

Ответы [ 2 ]

15 голосов
/ 19 апреля 2010

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

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

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

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

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

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

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

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

1 голос
/ 19 апреля 2010

Каждый поток имеет свой собственный объект диспетчера - возвращается 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();
...