Лучшая практика для рисования настраиваемых элементов управления в Winforms?

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

Я также где-то читал, что вместо того, чтобы воссоздавать эти ручки и кисти и т. Д., Чтобы создать их один раз как статические элементы, а затем удалить их один раз, когда форма закрыта, и т. Д.

Это лучшая практика?

Есть ли лучший способ для этого?

Я могу предположить, что, поскольку OnPaint вызывается 1000 раз (?) Раз, это создаст много работы для GC по сравнению с их созданием только один раз.


person Joan Venge    schedule 11.11.2009    source источник


Ответы (5)


Если кисти и ручки не меняются, безусловно, лучше создать их один раз и использовать повторно. Однако обратите внимание, что если ваш элемент управления может использоваться в нескольких потоках (что очень маловероятно), вам следует либо сделать их ThreadStatic (и инициализировать при первом использовании для каждого потока), либо сделать их членами экземпляра (и удалить их в Dispose переопределении вашего элемента управления. ); в противном случае вы получите невоспроизводимые ошибки GDI +, поскольку объекты GDI + не могут использоваться одновременно в нескольких потоках. То же самое и с изображениями.

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

Кстати, обратите внимание, что если вы используете обычные цвета, вы можете использовать статический _ 3_ и классы Pens , которые содержат статические кисти и перья для всех встроенных цветов .Net и _ 5_ и SystemPens для системные цвета.

person SLaks    schedule 11.11.2009
comment
Спасибо, еще один вопрос: когда и как вы вызовете метод Dispose элемента управления? Я никогда раньше не называл это на контроле. - person Joan Venge; 12.11.2009
comment
Вам не нужно называть это; .Net вызовет его, когда родительский элемент управления будет удален (когда вы удалите форму, в которой он находится). Если он находится в вашей основной форме, он будет удален в конце вызова Application.Run. - person SLaks; 12.11.2009
comment
Спасибо, Слакс. Еще одна вещь :) Поскольку я обычно использую только одну форму, если я создаю другую форму, которая не является основной формой, мне нужно избавиться от нее после ее закрытия? - person Joan Venge; 12.11.2009
comment
Формы автоматически удаляются при закрытии только в том случае, если они были показаны с помощью .Show или Application.Run (или эквивалентных). Формы, показываемые с помощью .ShowDialog, не удаляются при закрытии. - person homeInAStar; 12.11.2009
comment
@homeInAStar: Да, ты прав; Я недостаточно внимательно прочитал метод. При вызове ShowDialog лучше всего заключить код в оператор using. - person SLaks; 12.11.2009

В прошлом месяце я прочитал интересную статью, в которой предлагалось сделать все вашего рисунка на отдельный объект BufferedGraphics, и пусть метод on_paint выполняет прямую копию этого объекта в графический объект вашего элемента управления.

Таким образом, рисование выполняется быстрее, и вы обновляете свой BufferedGraphics только тогда, когда что-то существенно меняется (например, перемещается линия или изменяется текст).

person Jonathan    schedule 11.10.2010
comment
Хм, не так уж и хорошо. Он предполагает некоторые плохие вещи, такие как рисование полного элемента управления вместо обрезанного прямоугольника. В большинстве случаев это будет не самым быстрым. Кроме того, он вручную создает двойной буфер вместо использования ControlStyles.DoubleBuffer, предоставляемого системой, по-видимому, без всякой причины. Было бы неплохо извлечь код из обработчика OnPaint, но в этой статье есть дополнительные бонусные функции, которые не так хороши. - person David Suarez; 27.01.2011

Я бы сделал кисти и перья в качестве членов настраиваемого элемента управления, а затем избавился бы от них при удалении элемента управления. Таким образом, вы повторно используете одну и ту же кисть / перо каждый раз при вызове OnPaint.

Я бы не стал объявлять их static, потому что вы не сможете узнать, когда вы можете избавиться от своих объектов. Но, как упоминал SLaks, если в памяти одновременно находится много экземпляров элемента управления, может быть хорошей идеей создать кисти и перья как статические, чтобы у вас был только один экземпляр каждого объекта, созданного на время существования вашего приложения. .

person Meta-Knight    schedule 11.11.2009
comment
Если будет много экземпляров элемента управления, было бы неплохо сделать их статическими. Нет ничего плохого в том, чтобы повсюду валялась пара кистей. - person SLaks; 12.11.2009
comment
Это хороший момент, если существует много экземпляров этого элемента управления, неплохо было бы сделать кисти и перья статичными. - person Meta-Knight; 12.11.2009

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

Убедитесь, что у вас Dispose() все необходимое в вашей графике. Ручки, кисти, области, шрифты. Все это объекты GDI, привязанные к системе с помощью дескрипторов GDI.

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

И последнее, по крайней мере, для этого поста - не забудьте использовать двойную буферизацию, либо автоматическую в системе управления .net, либо стиль roll-your-own-back-bitmap.

Удачи GDI-ing :)

person Daniel Mošmondor    schedule 11.10.2010

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

person Sorin Comanescu    schedule 11.11.2009
comment
Только если он использует статические встроенные цвета. - person SLaks; 12.11.2009