What causes this ? Other controls are shown fine ...
public CustomControl()
{
SetStyle(ControlStyles.ResizeRedraw, true);
SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
SetStyle(ControlStyles.UserPaint, true);
}
The customcontrol is placed in a TableLayoutPanel.
...................
Edit: For clarification:
Suppose you have a window-sized control with a small modal dialog form on top. When you move the dialog window, it's like your painting with the window on the control (the borders are painted on the control). The control doesn't repaint itself like other controls do on the same form, ie montcalendar or other custom controls. I can't seem to find the cause of this ?
Small detail of drawing artifact:
Hard to tell from the snippet. The standard mistake is to draw through Control.CreateGraphics() instead of the OnPaint() method. Won't work, Windows lets the OnPaint method run when parts of the control get uncovered. Which wipes out whatever you drew. Another failure mode is deriving from a control that's a wrapper for a native Window control. UserPaint is not supported for these type of controls, the native Windows code has to do the drawing.
It is clear from the screen shot, note how the text is staggered. That's because the OnPaint() override is using the e.ClipRectangle property to figure out where to draw. That value always changes when you slowly drag a window across your control, it only tells you what part of the control needs to be redrawn. It does not tell you where to draw. That has to be based on the control bounds, routinely the rectangle from (0,0) to (ClientSize.Width, ClientSize.Height).
Only ever use e.ClipRectangle to optimize the drawing. Like skipping an expensive drawing detail when it is outside of the clipping rectangle. It is otherwise a small one, Windows is already quite good at clipping automatically.
Related
I have a control on my app that can be resized by the user, it has some button anchored to the top-right side and also a scrollbar.
The problem is that when the control is resized, the controls anchored to the right also changes the position, and only after a few ms the controls goes into the right place. So it looks like the child controls "shakes" while the parent control is resized.
I already tried all kind of things, like using SuspendLayout and ResumeLayout on the parent control, setting double buffering and other styles on each control to true, setting WS_EX_COMPOSITED bit, but nothing seems to make this issue go away.
This issue is present on other apps too, and is pretty annoying.
So is there anyway to fix that on .net?
Maybe making it render everything to a backbuffer, and then when everything is finished render it to screen?
I would create a new event that fires after resize is done, using a little timer magic stopping and starting a timer with an interval about 50ish ms on each resize event you can create this fake ResizeEnd kind of event.
On the first resize event I would stop the drawing of the UI using the dllimport call (dont recall which it was) to stop drawing the contents of your window or control. Then when the resize is done, enable drawing again using the same dllimport call.
The effect would be that it will only redraw itself after resize is done or every 50ms if you pause while resizing.
ResizeEnd: WinForms - action after resize event
SuspendDrawing: How do I suspend painting for a control and its children?
override the below virtual method from namespace using System.Drawing;
protected override Point ScrollToControl(Control activeControl)
{
return AutoScrollPosition;
}
should solve the problem !
I have a set of custom controls and a list of geometric objects that I need to draw on the same handle.
I override the OnPaint procedure, put the base.OnPaint(e) in the first line and commence with the drawing of the geometric objects (via e.Graphics.DrawLine etc.).
Those are in a locked list and decay after a while.
Also the customized controls can move around the window.
Now this is almost working as intended except for this fun fact:
The geometric shapes appear only after a control is moved along/above their layouts.
I was able to reproduce this in a small environment: PASTEBIN
I tried flushing the graphics object; save/restore; changing Clip.
Nothing seemed to work.
I am guessing that regions only get invalidated and repainted once a control is present. But how can I force them to be drawn anyways?
Control.Invalidate will tell the framework that the control needs to be redrawn. It does this automatically to redraw controls after, for example, the mouse has obscured part of it, but it will only redraw a the small section that the mouse covered (hence why you end up with a "(re)painting with the mouse" effect. Also moving a window will force it to redraw, as does covering it with another window and then moving that window away again.
But if you are doing a bunch of custom painting, you need to let it know that the control needs to be redrawn by calling Invalidate yourself.
I developed some components with their own OnPaint-override where I draw them.
I now added a status panel which is designed to overlap topmost with part of my form. I use a alpha-blended color to gray out the underlying controls and display a text on it.
Unfortunately some of my underlying custom controls paint themselves after the status bar and so draw themselves above the status bar. Debugging I found out that first the status bar on paint event was called, later the paint event of the underlying controls.
How can I make sure the proper order is used to paint?
When underlying components draw themselves the components infront of them should always be automatically invalidate so they redraw themselves but that is not happing. I also called SendToFront on the statusbar but that did not helper neither. So I am also asking what is the proper mechanism to maintain the order and how do the core components handle that.
Edit: I also run in this problem: With every run of my OnPaint-event my overlay gets more and more opaque because it draws with alpha=128--red again and again on itself.
To eliminate external factors (like variations between XP, Vista, Win7), you could:
blend the "status panel" graphics onto each control in their OnPaint handlers, so you don't need to mess about with a semi-transparent status window to achieve the desired display.
use one opaque control (essentially the status panel) and render the final image you want into it by compositing the graphics from the individual controls, which would elimimnate any uncertainty over how the rendering process will operate. This would mean that you'd have to add custom click handling, but that's usually a fairly trivial addition - one easy way around this is to put the main "display control" behind a set of invisible controls (the buttons) so that all the click handling can work as normal, but the painting is delegated to a single control.
I have a UserControl with a few buttons on it. I want to override OnPaint and paint some other stuff on the control.
So I override OnPaint.
Whenever OnPaint gets called the ClipRectangle is always {0,0,0,0} and so nothing I do gets drawn on the control.
What am I doing wrong?
Ok, Ive sussed it now. Its a bit silly. I had a TableLayoutPanel that was docked to the control. That seems to clip out all the areas that we can paint on.
I created a new control that derives from TableLayoutPanel and used this control instead. Its OnPaint gets the full clip rect.
However, that wasnt any use anyway... It seems I have misunderstood how Windows painting works. I thought I would be able to paint directly over the top of my controls, but this isnt the case. The controls get placed on top of my painting.
Gonna have to mess about with panels to get this working I reckon..
I have a Control that can overlay multiple C# user controls in my GUI. This control has a semi-transparent background in order to 'grey-out' portions of the GUI and the class looks somethink like this:
public greyOutControl: UserControl
{
// Usual stuff here
protected overide OnPaint()
{
paintBackround();
base.OnPaint();
}
}
Currently the control sometimes gets caught in a loop and constantly re-draws the background, making the semi-transparent color appear less and less transparent.
My idea to combat this is the following (in broad terms):
1) Determine what controls the greyOutControl is on top of
2) call Refresh() on those controls to update the display
3) continue drawing the greyOutControl.
My question is: How can I determine which controls the greyOutControl overlaps?, or is there a way that I can refresh only the part of the GUI that greyOutControl covers?
Why don't you keep track of your transparent controls and paint them after all the other controls are drawn?. Painting anything at the top of the Z-order shouldn't cause the other controls to be repainted.
I don't see a direct way of finding the overlapping controls. I think you might need to check the whole control tree to find out that. About refreshing, you can use Control.Invalidate(Rectangle) method to specify which part to refresh.
The solution to this problem I found was to programmatically take a screen shot of the area being overlayed and then use that image as the background for the control being overlayed. This then allows you to put the alpha overlay into the image within the OnPaint() method and the control to draw itself correctly.
This does have the disadvantage that the background isn't updated in the overlapping control, but unless there was a number of event handlers watching if something changes and then update the overlayed control I cant see any way around the issue. Sometimes I regret not trying to use WPF!