Измените свой код таким образом, чтобы перед вызовом Invalidate
для любого из трех элементов управления вы создали один общий буфер растровых изображений (предположительно в качестве статического члена вашего класса управления) и , а затем вызов Invalidate
на каждом из элементов управления. В событии Paint
элемента управления вы можете использовать статический буфер растрового изображения, и не имеет значения, в каком порядке запускаются события Paint
.
Когда вы вызываете Invalidate
для элемента управления, вы в основном говорите ОС отправить сообщение WM_PAINT этому элементу управления. Поскольку это сообщение Windows, оно гарантированно будет доставлено, когда Windows сможет это сделать. В вашем случае они обычно доставляются в полученном заказе, но иногда их просто не будет.
Еще одна вещь, которую следует учитывать в вашем коде: когда вы помещаете относительно сложный код рисования в обработчик событий Paint
вашего элемента управления (или внутри метода, вызываемого непосредственно из обработчика события Paint
), этот код будет выполняться всякий раз, когда элемент управления аннулирован по любой причине , что означает, что код будет запускаться при вызове Invalidate
, но он также будет запускаться всякий раз, когда над элементом управления будет перетаскиваться другое окно.
Для сложной, трудоемкой графики всегда лучше выполнять сложный рендеринг на скрытом буфере (Bitmap
или невидимом PictureBox
или чем-либо еще), а затем в событии элемента управления Paint
сделать простое скопировать из скрытого буфера в видимое окно (используя Graphics.DrawImage
или BitBlt
или любое другое).
Этот подход также позволяет избежать мерцания, если вы добавите второй буфер между буфером, на котором вы рисуете, и видимым окном (отсюда и «двойная буферизация»). После завершения рисования в главном буфере вы копируете его во второй буфер. В событии элемента управления Paint
вы копируете из второго буфера в видимое окно.