How to fix nested winform control flicker issues - c#

I am currently working on a program that uses a fairly complex structure of nested winform controls which changes dynamically as a user makes certain selections. To go into more detail about the specific layout of the controls would be to extensive for this question.
When ever a selection is made, a lot of updates are made to the underlying model which is controlled by the user controls. This then results in series of corresponding changes in the size/position/visibility of the displayed controls. All of these changes results in a painfully intense flickering of controls on the screen. I need to somehow fix this so that everytime the user makes a selection the screen is basically frozen until all of the control updates have completed.
I have attempted to use the Control.SuspendLayout/Control.ResumeLayout methods in many different places and ways and I can not eliminate the crazy flickering. I thought that suspending layout on the root control during the changes would fix the problem but it appears that this SuspendLayout doesn't help when child controls are changed.
Do I need to use some other approach rather than SuspendLayout? Is there a way I can debug SuspendLayout to see why it doesn't appear to be cascading to all of the child controls?

Suspend/ResumeLayout isn't your problem here. That only suspends automatic layout, the kind that is triggered by the Anchor and Dock properties. Double-buffering can't fix your problem either, that only suppresses flicker in each individual control. Your real problem is that you are updating too many controls at the same time, each will take its turn to paint itself and that takes time.
What you need is a different kind of double-buffering, compositing. Check out if the solution in this thread solves your problem.

In addition to #tommieb75's suggestion for double buffering, you can try and see if your root level controls have BeginUpdate/EndUpdate method pairs. These should help repress the repaints in between the calls.

If you are using WinForms 2+ then you can just set the 'Control.DoubleBuffer' property on the control to true (in the designer even).
With framework 2, setting DoubleBuffered sets the 3 flags : OptimizedDoubleBuffer, AllPaintingInWmPaint, and and another that I forgot, 'UserPaint' perhaps.
Also, do look at the BeginUpdate/EndUpdate as mentioned by #yetapb.

Use the SetControlStyles in the user Control, the flag is OptimizedDoubleBuffer which will prevent the flickering.

Related

Is it worth to show/hide existing form over creating new form every time?

Imagine we have:
1) some parent MainForm;
2) some child NewItemForm (called often).
What I think is: why would I use new NewItemForm() every time I need the form if I could create it once and set it's Visible property to true/false after on need (clearing the previous input ofc).
What I would want to know: personally I did not notice any difference however my sketchy knowledges tell me there should be some (memory allocation, controls initialization); support me please with your skill in
my doubts.
If the child controls are more or some third party controls pasted on the Winforms then it will take some seconds to load/initialize the form. If there is no control pasted or only .net controls then it is okay. Otherwise it will have performance issue while painting hide and show.

What is the very last event fired off during creation of a silverlight page

I know this may seem like an odd question, but I am after the information queried in the title.
So far I have tried LayoutRoot.Loaded, but found that LayoutRoot.LayoutUpdated happens even later.
My motivation for this knowledge is the ability to have one component interact with another in code, but for this to happen I must be guaranteed they both exist.
Any ideas?
Clarification of what I'm attempting to do:
I have a collapsing gridsplitter control. From here
When the main page loads I make it collapse; which shrinks the object preceding it to width 0. If that object isn't 'loaded' yet then it doesn't collapse and the gridsplitter is in an odd state where it thinks it has collapsed the item but needs two clicks to effectively do that.
LayoutUpdated is the last event raised in the control object initialization timeline. However keep in mind that LayoutUpdated will be raised multiple time subsequently as required. Maybe you can share a little more detail on what you are trying to do.

Why is there an OnResizeBegin for Forms, but not Controls?

A Windows Form is a type of Control, and Controls are UI elements that have a Size property along with size-related methods such as OnResize and OnSizeChanged.
But Forms also have OnResizeBegin (and OnResizeEnd), which are not found in Control. Is this omission an oversight, a prescient design decision, or something else entirely?
OnResizeBegin event is raised when form size is changed by user, not by programmaticaly changing Form properties (like Size). Most of controls can't be sized in such way, so it hasn't OnResizeBegin event.
When you add something to a base class like Control that has such a huge number of descendents, it's going to get inherited by everything whether it makes sense or not (e.g. would many programmers care that a radio button is starting to get resized?). Every method, property and event you add makes an API that much more complicated.
Now there are plenty of other examples of things in Control that don't make sense for every child (e.g. a Leave event on a Label control), but that's part of the contradictory morass that is Forms. The attached property system used in WPF is much more elegant.

How to draw a control, without drawing the control

I've got a list of UserControl objects; when a menu option is clicked to go to another section of the application it does the following:
Set the currently displayed usercontrol to visible
Clear the main panel's Controls list
New up the requested control (if not already created in the list)
Add the new control to the main panels' Controls list
Dock the new control to fill
Set the new control to visible
I did this because, previously all of the areas of the application were not user controls and they were just collections of controls in a TabControl. The underlying code was monstrous (the code in frmMain was 13000+ lines).
It works well. All controls (what each tab page would have been before) manage their own behaviour, each control has a small code footprint. I can have a sexy menu. All good things.
However, obviously there's a problem. Before, the tabcontrol would load on startup, and all tabs would render (but weren't seen). One tab page in particular has a scheduling control on it and it takes a good 3-4 seconds to draw and adjust its layout. Now that controls are loaded and shown as they're needed, the first time you view this particular control, you see it load and adjust its size/formatting/etc. Which is hardly esthetically pleasing.
My question is, how can I load and render this control so that it'll render and figure out its layout, but without it actually showing the user?
I've tried simple things like:
ScheduleWindow scheduler = new ScheduleWindow() { Visible = false; }
mainPanel.Controls.Add(scheduler);
scheduler.Visible = true;
I've tried creating and loading the control on its own thread (with numerous difficulties) and it still didn't do anything...
Is there any way to achieve what I'm looking for?
Try using the SuspendLayout() and ResumeLayout() methods on the main form? When you call SuspendLayout(), you can do whatever you need to do with the controls you are adding, such as docking, resizing, etc. When you call ResumeLayout(), all changes will be applied at once, and should happen instantaneously.
Alternatively, some controls have a BeginUpdate() and EndUpdate() method, which suspend redraws for that control, allowing you to do heavy work (such as adding thousands of items to a ListView) without seeing the updates happen live. This also improves performance, as rather than redrawing every time the control is changed, you batch changes, then redraw once.
Try calling scheduler.Handle.ToString() and/or scheduler.Refresh().

Flickering during updates to Controls in WinForms (e.g. DataGridView)

In my application I have a DataGridView control that displays data for the selected object. When I select a different object (in a combobox above), I need to update the grid. Unfortunately different objects have completely different data, even different columns, so I need to clear all the existing data and columns, create new columns and add all the rows. When this is done, the whole control flickers horribly and it takes ages. Is there a generic way to get the control in an update state so it doesn't repaint itself, and then repaint it after I finish all the updates?
It is certainly possible with TreeViews:
myTreeView.BeginUpdate();
try
{
//do the updates
}
finally
{
myTreeView.EndUpdate();
}
Is there a generic way to do this with other controls, DataGridView in particular?
UPDATE: Sorry, I am not sure I was clear enough. I see the "flickering", because after single edit the control gets repainted on the screen, so you can see the scroll bar shrinking, etc.
People seem to forget a simple fix for this:
Object.Visible = false;
//do update work
Object.Visible = true;
I know it seems weird, but that works. When the object is not visible, it won't redraw itself. You still, however, need to do the begin and end update.
The .NET control supports the SuspendLayout and ResumeLayout methods. Pick the appropriate parent control (i.e. the control that hosts the controls you want to populate) and do something like the following:
this.SuspendLayout();
// Do something interesting.
this.ResumeLayout();
Double buffering won't help here since that only double buffers paint operations, the flickering the OP is seeing is the result of multiple paint operations:
Clear control contents -> repaint
Clear columns -> repaint
Populate new columns -> repaint
Add rows -> repaint
so that's four repaints to update the control, hence the flicker. Unfortunately, not all the standard controls have the BeginUpdate/EndUpdate which would remove all the repaint calls until the EndUpdate is called. Here's what you can do:
Have a different control for each data set and Show/Hide the controls,
Remove the control from its parent, update and then add the control again,
Write your own control.
Options 1 and 2 would still flicker a bit.
On the .Net GUI program I'm working on, I created a set of custom controls that eliminated all flicker.
Rather than adding the rows of the data grid one at a time, use the DataGridView.Rows.AddRange method to add all the rows at once. That should only update the display once. There's also a DataGridView.Columns.AddRange to do the same for the columns.
This worked for me.
http://www.syncfusion.com/faq/windowsforms/search/558.aspx
Basically it involves deriving from the desired control and setting the following styles.
SetStyle(ControlStyles.UserPaint, true);
SetStyle(ControlStyles.AllPaintingInWmPaint, true);
SetStyle(ControlStyles.DoubleBuffer, true);
Sounds like you want double-buffering:
http://www.codeproject.com/KB/graphics/DoubleBuffering.aspx
Although this is mainly used for individual controls, you can implement this in your Windows Forms control or Form.
Unfortunatly, I think that thins might just be a by-product of the .net framework. I am experiencing similar flickering albeit with custom controls. Many of the reference material I have read indicates this, alongside the fact the the double buffering method failed to remove any flickering for me.
You may also try this, its work.
public static void DoubleBuffered(Control formControl, bool setting)
{
Type conType = formControl.GetType();
PropertyInfo pi = conType.GetProperty("DoubleBuffered", BindingFlags.Instance | BindingFlags.NonPublic);
pi.SetValue(formControl, setting, null);
}

Categories