3

In my user control I perform a lengthy operation. In order to prevent users from clicking the UI, I show a progress bar and I disable the whole UI, like this:

this.Enabled = false;
ShowProgressBar();
DoLengthyOperation();
RemoveProgressBar();
this.Enabled = true;

This works OK. However, my user control has many other controls on it, which also have controls inside them, which also have controls inside them,... etc. The

this.Enabled = false 

call thus disables many many controls. This is intentional. But the problem I have is that you can actually see the UI disabling every control one by one. It goes pretty fast but since there are so many controls, you can actually see it running through all the controls. This does not look professional, it makes the screen flicker and my eyes hurt.

Is there a way so that I can prevent the UI from redrawing until all controls are disabled and then perform a single redrawing?

I hope this is not a stupid question ;)

Don't know if this is relevant: my controls are derived from DevExpress.XtraEditors.XtraUserControl.

Bart Gijssens
  • 1,572
  • 5
  • 20
  • 38
  • 1
    I don't know if it will help, but you can try `this.SuspendLayout()` before the `this.Enabled = false;` and 'this.ResumeLayout()` after. That's supposed to stop everything from processing layout changes. I'm not sure though, if the enabling/disabling is considered a layout change or a painting change. Otherwise I think you'd have to catch and stop all the `OnPaint` events. – CodingGorilla Sep 22 '11 at 13:54
  • Actually I think my question is a duplicate of this one:http://stackoverflow.com/questions/487661/how-do-i-suspend-painting-for-a-control-and-its-children I have not yet tried that solution. – Bart Gijssens Sep 23 '11 at 11:25

5 Answers5

4

Have you tried the Form.SuspendLayout and Form.ResumeLayout? It seems like what you need. There is more information on the msdn site here.

You call suspendlayout before you want to re-draw and then resume once you have disabled all the controls.

this.SuspendLayout();
ShowProgressBar();
DoLengthyOperation();
RemoveProgressBar();
this.ResumeLayout();

If the progress bar is on the form, you will have to 'show' it before you suspend the layout. Sorry, I missed that.

nbz
  • 3,806
  • 3
  • 28
  • 56
3

try this:

this.Invalidate();  // Invalidate the whole window
this.Enabled = false;
this.Refresh(); // Redraw every invalidated part of the window, so everything
Marco
  • 56,740
  • 14
  • 129
  • 152
  • This does not seem to have any effect. – Bart Gijssens Sep 23 '11 at 06:08
  • Oh I'm sorry... I found this on stackoverflow which seems similar to what you want to do, http://stackoverflow.com/questions/487661/how-do-i-suspend-painting-for-a-control-and-its-children/487757#487757 – nbz Sep 23 '11 at 08:39
2

None of the suggestion solutions seems to work.

I think part of the problem is that I use DevExpress and every control does not directly contain its subcontrol, but uses LayoutControlGroups and LayoutControls and panels etc. The actual amount of controls used is thus a lot higher than the actual controls that you see on the screen and that need to be disabled.

So I just added my own recursive function that disables only controls of certain types, in my case Buttons and Edit boxes. The rest is just ignored. Not only is this a lot faster, it also looks much nicer. No flickering at all any more.

I think I'm going to use this solution, but I do appreciate the effort of everyone who put an answer or a comment here, thanks!

Now I see that my question seems to be a duplicate of this one: How do I suspend painting for a control and its children? Haven't tried that solution tough.

Community
  • 1
  • 1
Bart Gijssens
  • 1,572
  • 5
  • 20
  • 38
1

You can try and add double buffering to your controls. This will not stop the painting. However, it should help with the visual portion of your issue.

System.Reflection.PropertyInfo aProp =
        typeof(System.Windows.Forms.Control).GetProperty("DoubleBuffered",
        System.Reflection.BindingFlags.NonPublic |
        System.Reflection.BindingFlags.Instance);
 aProp.SetValue(YourControlNameHere, true, null);

Note: Most controls already have this set to true by default. Your usercontrol may not, so you can test to see if this helps or not.

Billy
  • 2,600
  • 6
  • 31
  • 36
  • Is that different to just DoubleBuffered = true;? – Bart Gijssens Sep 23 '11 at 06:35
  • BaGi: it seems to be the same, only performed via .net reflection :-) – naivists Sep 23 '11 at 11:25
  • DoubleBuffered = true only works for some controls... Many of the microsoft controls have that property set to protected. So you can't modify it thru the property. I've ran into issues with the ListView control flashing when adding items or removing them. – Billy Sep 23 '11 at 14:30
0

You can place controls into a container (call it groupControls), Turn the container's visible property to false, (have a splash screen appear or equivalent size container with "updating" or whatever become visible - call it groupUpdateSplash) update your controls turn off splash container visible and turn on your control container visible

groupControls.visible = false
groupUpdateSplash.visible = true
/* update controls and everything */
groupUpdateSplash.visible = false
groupControls.visible = true
Georg
  • 404
  • 5
  • 7