Проблемы управления WPF - PullRequest
1 голос
/ 30 июня 2010

Я столкнулся с одной проблемой, из-за которой приложение WPF не может обновить индикатор выполнения, даже если кнопка в окне wpf перестает светиться до тех пор, пока я не переместлю окно, тогда все в порядке.я обновляю индикатор выполнения, который фактически генерирует сообщение WM_PAINT, но не решает проблему.Эта проблема является случайной, иногда случается, что иногда не происходит.

Мое приложение использует DirectShow в сочетании с улучшенным рендерингом видео для рендеринга видео.Если я заменю Enhanced Video Renderer на VMR, все будет нормально.

Буду признателен, если кто-нибудь мне поможет.

Спасибо, Сохраб.

1 Ответ

7 голосов
/ 03 июля 2010

Я понимаю, почему вы пытались исправить ошибку WM_PAINT.Однако WM_PAINT действительно не имеет никакого отношения к рендерингу WPF вообще.

По сути, вот как WPF выполняет рендеринг, когда на экране впервые отображается окно (или HwndSource, ElementHost, ...):

  1. Объект Window имеет видимость, установленную на «Видимый»
  2. Окно Win32 (hWnd) выделено и показано, но его WM_PAINT игнорируется
  3. Поверхность Direct3Dвыделенный для покрытия области окна Win32
  4. Обратный вызов Dispatcher запланирован на DispatcherPriority.Render
  5. Когда срабатывает обратный вызов Dispatcher, визуальное дерево окна измеряется и упорядочивается
  6. Во времяпроход аранжировки каждый элемент управления генерирует инструкции рисования для рисования самого себя и сохраняет их в DrawingContext
  7. . В конце прохода аранжировки WPF считывает данные DrawingContext и использует Direct3D для обновления экрана

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

Ключевой момент, на который следует обратить внимание, заключается в том, что каждый раз, когда требуется выполнить рендеринг, должен выполняться обратный вызов Dispatcher.Это означает, что ваш пользовательский интерфейс будет продолжать отображаться до тех пор, пока:

  1. Диспетчер обрабатывает свою очередь и
  2. Вы не добавляете непрерывно диспетчерские операции с приоритетом рендеринга или выше

Кроме того, обработка входных событий происходит с приоритетом ввода, поэтому вам нужно, как минимум, разрешить Диспетчеру выполнить приоритет до приоритета ввода, если вы хотите, чтобы на кнопках работала мышь.

Из-за того, как работает WPF, отправка WM_PAINT вообще ничего не делает.То, что вы хотите сделать, это дать Диспетчеру возможность обработать свою очередь.Обычно это делается путем вызова Dispatcher.Invoke из потока пользовательского интерфейса и передачи приоритета ниже, чем события, которые вы хотите сбросить, например:

Dispatcher.Invoke(DispatcherPriority.ApplicationIdle, new Action(() => {}));

Обратите внимание, что действие вообще ничего не делает.Но вызов Dispatcher.Invoke не может вернуться, пока не выполнится пустое действие, и пустое действие не может быть выполнено, пока не будут выполнены все действия с более высоким приоритетом.Таким образом, приведенный выше код приводит к тому, что рендеринг происходит синхронно, аналогично тому, что происходит при выполнении SendMessage (WM_PAINT, ...) в Win32.

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

...