Как правильно использовать OnPaint в приложениях.Net?
Иногда мне нужен внешний вид элемента управления. Или сделайте много заказной живописи. Я знаю, что могу сделать это с OnPaint
(см.: http://msdn.microsoft.com/en-us/library/system.windows.forms.control.onpaint.aspx)
Как правильно рисовать вещи в приложении.net, используя OnPaint
? Есть ли какие-то правила, которые я должен соблюдать, чтобы оптимизировать свое приложение и минимизировать время рендеринга?
Примечание: время от времени я видел и испытывал много неэффективного использования OnPaint, поэтому я создал этот вопрос и ответ.
1 ответ
Использовать OnPaint
для того, чтобы эффективно вы знали пару вещей:
-
OnPaint
контроля, например,Form1
, выполняется каждый раз, когда элемент управления окрашен (дух...) -
OnPaint
изForm1
выполняется каждый раз, когда дочерний элемент управленияForm1
нарисован. Например, если вы рисуете точку в правом верхнем углуForm1
с использованиемOnPaint
изForm1
в то время как у вас есть 150 дочерних элементов управленияForm1
, точка будет нарисована не менее 150 раз! Это значительно увеличивает время рендеринга. Особенно, если вы делаете много пользовательских чертежей и расчетов вOnPaint
,- Так что, как правило, вы никогда не должны иметь никакой логики в
OnPaint
элемента управления, когда этот элемент управления имеет один или несколько дочерних элементов управления. Вместо этого вы должны создать собственный элемент управления, в котором больше нет дочерних элементов управления, который выполняет рисование. И поместите его в качестве дочернего элемента управления в родительский элемент управления в том месте, где требуется пользовательский чертеж. - Всякий раз, когда элемент управления добавляется к родителю, родитель перерисовывается. Если вы поместите много элементов управления на другой элемент управления, например, большой набор результатов с флажками на
Form1
, вы должны использоватьForm1.SuspendLayout()
(см. http://msdn.microsoft.com/en-us/library/system.windows.forms.control.suspendlayout.aspx) перед добавлением дочерних элементов управления. А такжеForm1.ResumeLayout()
когда вы закончите добавлять элементы управления. Это временно подавляетOnPaint
событие, и уменьшает время рендеринга. - Прозрачные пленки всегда увеличивают время рендеринга.
- Размещение компонентов таким образом, что между ними нет фона, уменьшает количество
OnPaint
события в родительском контроле. Например, поместите 4 текстовых поля ниже друг друга, чтобы они касались друг друга. Таким образом, между ними нет фона, а все элементы управления нарисованы в одномOnPaint
событие вместо 4OnPaint
События. Конечно, это не всегда возможно, так как вы не хотите склеивать все свои компоненты рядом. Но это стоит делать, если производительность важнее, чем внешний вид, например, в большой пользовательской "сетке данных" какого-то рода. - НИКОГДА не меняйте расположение или размер элемента управления в
OnPaint
событие, так как это вызывает новыеOnPaint
События. Если вы должны переместить / изменить размеры элементов управления, вам придется добавить это где-то еще в вашем коде, доOnPaint
вызывается. Например, поместите код перемещения / изменения размера вOnLayout
или жеOnResize
или подобные события. Если вы все еще думаете, что вы должны поместить этот код перемещения / изменения размера вOnPaint
Событие для того, чтобы ваше приложение работало, чем вы не правы, и вам нужно пересмотреть логику вашего кода. - Подумайте System.Math.Pow(2, 2), прежде чем вызывать Refresh() для элемента управления вне его собственного класса. Если у вас есть желание вызвать Refresh, вам, вероятно, нужны новые события и обработчики событий, чтобы синхронизироваться с тем, что вы хотите отобразить. Это также относится и к Invalidate().
- Чтобы проверить, насколько хорошо вы рисуете, вы можете сделать следующее. 1. Откройте ваше приложение. 2. Поместите точку торможения на OnPaint в верхней части списка. 3. Максимизируйте окно, чтобы оно охватывало ваше приложение. 4. Сверните окно снова, и ваше приложение перерисовает элемент управления. Если вещи нарисованы дважды, вы допустили ошибку в логике вашего приложения.
- Так что, как правило, вы никогда не должны иметь никакой логики в
Ну, вот и все, если что-то придет в голову, что я забыл, я обновлю этот вопрос и ответ. Если я что-то забыл или допустил ошибку, я был бы рад принять это к сведению!
Надеюсь, это даст кому-то преимущество в использовании пользовательских инструментов рисования в.Net, поскольку я искал эту информацию некоторое время назад.