OnRender не вызывается после InvalidateVisual()
Пользовательский элемент управления WPF переопределяет OnRender. Метод генерирует и отображает путь из пользовательских данных. Поставщик данных связан с использованием свойства зависимости. Свойство Dependency регистрирует событие при изменении данных. Это событие в свою очередь вызывает InvalidateVisual().
Однако после InvalidateVisual () OnRender вызывается не всегда.
Мы используем Prism Framework и Regionall. Соответствующий элемент управления встроен в такой регион, который активируется и деактивируется. Однако свойство элемента управления "IsVisible" имеет значение true, когда регион активен. Но все же при вызове InvalidateVisual () метод OnRender не вызывается...
Что может помешать вызову метода OnRender?
3 ответа
У меня тоже была эта проблема.
контекст
У меня есть множество элементов управления, основанных на компонентах графика DynamicDataDisplay внутри VirtualizingStackPanel (внутри ListBox).
Когда есть больше элементов управления, которые видны одновременно, но их недостаточно для того, чтобы VirtualizingStackPanel начал повторно использовать их при прокрутке, я вижу эту проблему с классом D3 AxisControl. По какой-то причине он выполняет большую работу в своем методе OnRender, который он пытается вызвать, вызывая InvalidateVisual, когда что-то меняется.
В проблемном случае проблемные элементы управления вызывают InvalidateVisual, но они никогда не получают вызов MeasureOverride, ArrangeOverride или OnRender. Интересно, что большинство элементов управления все еще работают, в одном конкретном случае я получаю последние 3 из набора из 11, которые не работают должным образом. В частности, те 3 (и только те 3) получают вызов MeasureOverride непосредственно перед обновлением привязки данных, которое инициирует вызов InvalidateVisual.
Мое исправление
В конце концов мне удалось это исправить, добавив вызов InvalidateMeasure вместе с вызовом InvalidateVisual.
Это ужасное решение, но оно не является критически важной частью нашего приложения, поэтому мне, похоже, это сходит с рук.
Если размер вашего контроля остается прежним, вы не должны использовать InvalidateMeasure()
или же InvalidateVisual()
потому что они вызывают дорогостоящую перепланировку.
WPF - это сохраненная система рисования. OnRender()
может быть лучше назвать AccumulateDrawingObjects()
потому что это на самом деле не рисует. Он накапливает набор графических объектов, которые WPF использует для рисования вашего интерфейса в любое время. Волшебная вещь, если вы положите DrawingGroup
в DrawingContext
в течение OnRender()
вы можете эффективно обновить его после OnRender
в любое время.
Смотрите мой ответ здесь для более подробной информации..
/questions/47790754/kak-pererisovat-ili-obnovit-v-onrender/47790769#47790769
У меня тоже была эта проблема.
У меня была полоса прокрутки для элемента управления, которая только выясняла, сколько места действительно необходимо для отображения всего содержимого, которое могло быть больше, чем доступное пространство для отображения, и для этого требовалась полоса прокрутки. Может случиться так, что вызываются некоторые методы, которые в конечном итоге изменяют значение полосы прокрутки, с которой должно было начинаться.
Однако после этого мне больше не звонили. Я думаю, причина в том, что
InvalidateVisual()
устанавливает некоторые флаги, которые сообщают WPF, что элемент управления необходимо снова нарисовать, но после завершения этот флаг сбрасывается. Вот какой-то псевдокод, как я ожидаю:
//someCode:
control.InvalidateVisual()
//code of InvalidateVisual()
control.RedrawFlag = true;
//WPF some time later:
if (control.RedrawFlag){
control.OnRender()
//OnRender code
//do some stuff
//decide control needs to be redrawn
//however, RedrawFlag is alreday true!
//next line is not changing anything
control.RedrawFlag = true;
//WPF finished executing control.OnRender
control.RedrawFlag = false;
}
Я больше не исследовал, действительно ли WPF работает таким образом, но это объясняет, почему он не вызывается во второй раз.
Вместо того, чтобы тратить еще больше времени, я изменил способ вычисления общей ширины содержимого элемента управления и поместил этот код за пределы
OnRender()
.