Custom Control Painting Sequence

aliassce

Newcomer
Joined
Jul 20, 2005
Messages
16
Hi,
I'm developing a class derived from Panel Control. It's Transparent, moveable and resizeable. When moving or resizing (onMouseMove event) it draws a Temperory rectangle over the parent control. I
Adding a single control to a form from this class isn't a problem. But when I add multiple controls on a form I have a problem. If I move a control the others that are added later are not painted. Let's say I have 3 controls If I move the third one everything is normal. If I move the second one the third doesn't paint during movement. If I move the first one the second and third don't paint.. After the movement everything comes back.
I think the problem is my later added controls doesn't receive painting calls. I wonder is there a hierarchy according to adding order of controls.

Thanks advance.
 
Hi there,

First of all WinForms doesn't support real transparency. An image is created in the paint event from the colors beneath the object and uses that as it's background. So WinForms might have some paint-problems if you use several transparent object drawn on eachother.

Secondly if your mousemove keeps calling there might be no time left for repainting before your next mousemove call.

If you still encounter problems please post some code, and we'll see what we can do :)

~ DP
 
Thanks for comment.
But actually my problem is not just transparency. While a control is drawing a rectangle on parent form another controls that are added after this are not painted.

My code looks like this

public class MyControl : Panel

{

public MyControl()

{
SetStyle(ControlStyles.SupportsTransparentBackColor, true);
SetStyle(ControlStyles.Opaque, true);
this.SetStyle( ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint ,true);
}

protected override void OnPaint(PaintEventArgs e)

{
// Draw some graphics on this object
// Graphics g= e.Graphics
// ...................

if (IsSMoving)
{
Graphics g2 = this.Parent.CreateGraphics();

// g2.DrawRectangle(); Here we draw a temporary rectangle on parent (Form)
this.Parent.Invoke();
}
base.OnPaint(e);

}

}
}

____________________________

On a form I add some objects from this class. But if a control is moving the ones added later are not shown until it stops moving.
 
try to trace some messages in the Paint handling code
ie.
Trace.WriteLine("panel" & id & "painted!");

where you give each panel a temporary id.
this way you can determine in your immediate window if your panel gets its paint event. if it does you can step through your code with a breakpoint under the condition that the id matches the third or second panel. This way your breakpoint only breaks on paint events of your 'incorrect' panels. Please share your results.

~DP
 
Thanks for answer.

I put Debug.WriteLine (this.name + "painted" ) ;
in paint event.

If I move the first added control the output is:
c1 painted
c1 painted
c1 painted
.............
c1 painted
c2 painted
c3 painted

if I move the second added one the output is
c2 painted
c1 painted
c2 painted
c1 painted
..............
c2 painted
c1 painted
c3 painted


if I move the last added (third control)
c3 painted
c1 painted
c2 painted
..........
c3 painted
c2 painted
c1 painted


So, each control prevents the painting of other controls. Now I realized that The problem is about this.Parent.Invoke() method. In each paint event my control paints a graph on parent and calls this method. The parent calls the control paint methods in a queue and when it reaches the current control, it receives the invoke call and starts from the first control again.
The question is how can I prevent this endless loop while I can paint something on parent control.

Thanks
 
Why I'm setting Opaque, just because to find a solution. I know it's not a clever way. Otherwise only the first control is painted. But I need to find a solution for parent -> child , child >parent endless Invalidate() calls.
 
There is something fundamentally wrong with your method if yau are getting this recursion. It seems to me that a control shouldn't be drawing to anything but itself in the Paint event. I'm not sure exactly what you are trying to achieve.
 
It may be wrong but I was trying to draw a temporary rectangle over the parent control during movement and resizing events. The temporary rectangle is drawn on parent control and onMouseUp my control places itself on this rectangle. Actually if you have a better solution please help me.
Thanks.
 
Maybe the control can handle its parent's paint event and do the rectangle drawing there. To do this you would have to explicitly invalidate the parent whenever the rectangle moves, and the result may not necessarily look that good.

You could also try to draw the rectangle outside of the paint event, but if your control is transparent it wont look right when they overlap.
 
Thanks a lot. If I invalidate the parent it tries to draw itself and the childs whatever parameter I pass to Invalidate() method. This causes my control call the parent invlidate() againd which starts the problem
 
It seems to me that you don't have a great handle on the way that control painting works. I understand that it's not that simple. Consider these tips.

Your control should not be invalidating anything while it is painting, especially its parent. Painting is the result of invalidation, and not vice-versa.

A control should not be drawing to anything but its own client region using the provided graphics object when painting.

You should not explicitly invoke the Paint event or the OnPaint method. Windows will invoke these for you when a control is invalidated.

You should only be invalidating a control when its visual state does not represent it's logical state (i.e. it is invalid, and therefore should be painted). A control should not invalidate its chrilden. Windows does this for you automatically.
 
Thanks, I think I can find better methods. Now I see that invalidating while painting is a great mistake.
 
Back
Top