How to remove controls from a container without container updating - c#

I have an ordinary Panel control with a bunch of user controls contained within. At the moment, I do the following:
panel.Controls.Clear();
but this has the effect that I see (albeit quickly) each control disappearing individually.
Using SuspendLayout and ResumeLayout does not have any noticeable effect.
Question: Is there a way I can remove ALL controls, and have the container update only when all child controls have been removed?
Edit: the controls I am removing are derived from UserControl, so I have some control over their drawing behaviour. Is there some function I could possibly override in order to prevent the updating as they are removed?

Thank you Hans for your suggestion - yes, it turns out I was leaking controls.
Here's what I ended up doing:
panel.Visible = false;
while (panel.Controls.Count > 0)
{
panel.Controls[0].Dispose();
}
panel.Visible = true;
Basically, I hide the entire panel (which is border-less) before I dispose of each control. Disposing of each control automatically removes said control from the parent container, which is nice. Finally, I make the container visible once more.

What I think you need is Double Buffering.
There are several answers concerning this already on SO like
Winforms Double Buffering,
Enabling Double Buffering
and
How do I enable double-buffering of a control using C# (Windows forms)?
SuspendLayout stops the control redrawing as the children are removed but those actions are still processed in order when you call ResumeLayout. Double Buffering will stop the control painting at all until the offscreen buffer is updated. The update won't happen any quicker but it will be rendered to screen all at once from the buffer. If your machine is very slow you might still get a flicker when the buffer is rendered to the screen, like you would when loading a picture.

Related

c# anchored controls "shakes" while resizing

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 !

Double Buffer a custom control in the Compact Framework

I have a custom control that inherits from Panel. I end up putting several DataGrids and Labels on this panel. When it gets too long it auto scrolls for me.
I really need the scrolling because it is a list of scanned in objects that will grow larger than the space on the screen will allow.
But when I scroll it flickers quite a lot. I would love to have it give me some smooth scrolling.
I have seen several "Compact Framework" double buffer examples out there, but they all are double buffering draw methods (ie graphics.DrawString). My custom control does not do any painting by itself. It just puts normal grids and labels on the panel and lets the panel paint them.
Is there a way to double buffer normal controls (again NOT custom painting)?
The Compact Framework Controls do not have the DoubleBuffered property or the underlying double-buffering mechanism. There's no way to add it either.
The only way to get double-buffering is to override the painting of the control and do your own.

C#: Scroll/AutoResize child controls in custom control, slow repaint

I'm currently writing an custom control which has to hold child control and have to support scrolling and autorisze.
Autoscrolling is not possible because my control is fully selfpainted an only a part of the control should be scrolled.
Now the the repainting of the Controls is extrem slow, especialy with textbox and buttoncontrols with systempainting. Deactivating systempainting (TextBox.BorderStyle = Borderstyle.Fixed) helps, but the control should also support this. Using SetRedraw and updating the controls afterward doesn't help, because the textbox systemdraw is ignored and the textbox looks ugly. Refreshing my whole control or using `RedrawWindow slows the painting down again.
i also already tried to suspend my control and child controls layout without success.
Does anybody know how to speedup the childcontrol painting like AutoScrolling.
My CustomControl has the Style ControlStyles.AllPaintingInWmPaint | ControlStyles.SupportsTransparentBackColor | ControlStyles.OptimizedDoubleBuffer.
The ChildControl bound is changed on (MyControl)Resize and (ScrollBar)OnValueChanged.
Using a Timer helps a little, but i don't know if this is realy the right solution.
EDIT :
I have found the problem, aufter reactivating SetRedraw and Refresh, OnPaint fires 38 times with 37 Controls. Is the any workaround?
It gets slow with that many controls, 37 of them is just rather a lot. For comparison, Microsoft Outlook uses about 50 windows, you've got 38 for just a control. It gets extra slow because of transparency effects on those controls. The OnPaint() method runs so often to provide the background pixels of the controls. You can't always fix that, a Button for example is going to let its parent draw the background even if it is not transparent. Controls are very convenient but they are not cheap.
Only one way to really get ahead here: stop using so many controls and stop trying to support transparency. Not sure what you use, but a Label for example is especially wasteful. Using TextRenderer.DrawText in your OnPaint method also can draw a label, minus the cost of a Control.
I was able to speed it up, by adding a custom flag which tells me if the OnPaint is fired by my control or by a child control. If my control fires the event i draw my controls content to a bitmap and just blit it for the childcontrols.

Stop controls from being painted

I have a User Control that has some WinForm Controls inside. I want to be able to paint those inner controls myself (for scrolling purposes, some of them will remain, others will move).
Even when I override the OnPaint and the OnPaintBackground method, those controls keeps showing on my usercontrol which is completely black now because there is no painting methods on it.
Is there a way I can suppress those controls from been painted and then paint them by myself with the DrawToBitmap method of each control?
Yes. Remove them from (or better yet, never add them to) the UserControl's set of child controls. Simulating interaction with the controls is going to be a PITA, though.
Do you just need the controls to "look" like they're there. Or do they need to actually be there? If its the latter, you would be better off faking the scrolling somehow by just repositioning the controls manually.
Trying to re-invent the windowing system is an exercise in pain. You will be better off if you learn and work within its paradigms.
If you don't need interaction, just set every child control .Visible = false.
Otherwise, have you tried WM_SETREDRAW?

c# Winforms: Refreshing a portion of a GUI (containing 1 or more controls)

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!

Categories

Resources