views:

197

answers:

2

I have 3 data graphs that are painted via the their paint events. When I have data that I need to insert into the graph I call the controls invalidate() command.

The first control's paint event actually creates a bitmap buffer for the other 2 graphs to avoid repeating a long loop.

So the invalidate commands are in a specific order (1,2,3). This works well, however when the graphed data reaches the end of the graph window (PictureBox) where the data would normally start scrolling, the paint events begin firing in the wrong order (2,3,1).

has anyone came across this before? why might this be happening?

+4  A: 

Change your code so that before calling Invalidate on any of the three controls, you create the one shared bitmap buffer (conceivably as a static member of your control class), and then call Invalidate on each of the controls. Within the control's Paint event you can then use the static bitmap buffer, and it won't matter in which order the Paint events fire.

When you call Invalidate on a control, you're basically telling the OS to send a WM_PAINT message to that control. Because it's a Windows message, it's guaranteed to be delivered whenever Windows gets around to doing it. In your case, they're usually delivered in the order received, but sometimes they just won't be.

One other thing to consider with your code: when you place relatively complex drawing code inside your control's Paint event handler (or inside a method called directly from the Paint event handler), this code will execute whenever the control is invalidated for any reason, meaning that the code will run when you call Invalidate, but it will also run whenever another window is dragged over the control.

For complex, time-consuming graphics, it's always best to perform the complex rendering on a hidden buffer (a Bitmap or an invisible PictureBox or whatever), and then in the control's Paint event do a simple copy from the hidden buffer to the visible window (using Graphics.DrawImage or BitBlt or whatever).

This approach also allows you to avoid flicker, if you add a second buffer in between the buffer you draw on and the visible window (hence "double buffering"). After you complete drawing on the main buffer, you copy it onto the second buffer. In the control's Paint event, you copy from the second buffer onto the visible window.

MusiGenesis
Sorry, my bad. I didn't look at the time stamp. The post wasn't presented by posting order when i made the tick. lesson learned
Luke Mcneice
@Luke: you can give the check back to Virtlink - I've got plenty of rep points, and he was right too. :)
MusiGenesis
+3  A: 

Because calling Invalidate() on a control essentially asks the operating system to schedule the control for redraw, there is no guarantee that this is done in a specific order.

Since you attempt to call Invalidate() in a specific order, I assume that you have a single method which does this. You could add code just before these calls to draw the bitmap buffer which is then used by the invalidated controls. I don't know if this may ever occur, but this also gives you the freedom to not invalidate a control when it's data doesn't change. Furthermore, controls can be invalidated at any time. For example, moving a form across Control 1 causes it to invalidate, and in your current setup, recalculate the buffer bitmap while that is not required. Therefore, you should separate this functionality.

Virtlink
Just to whine a little while I wait for the beer to kick in: this is exactly what *I* said, 5 minutes earlier. :)
MusiGenesis