How to fix the flickering in User controls

后端 未结 12 1348
佛祖请我去吃肉
佛祖请我去吃肉 2020-11-22 02:32

In my application i am constantly moving from one control to another. I have created no. of user controls, but during navigation my controls gets flicker. it takes 1 or 2 se

相关标签:
12条回答
  • 2020-11-22 02:45

    Did you try Control.DoubleBuffered Property?

    Gets or sets a value indicating whether this control should redraw its surface using a secondary buffer to reduce or prevent flicker.

    Also this and this might help.

    0 讨论(0)
  • 2020-11-22 02:46

    There is no need of any Double buffering and all that stuff guys...

    A Simple solution...

    If you are using MDI Interface, just paste the code below in the main form. It will remove all flickering from the pages. However some pages which require more time for loading will showup in 1 or 2 secs. But this is better than showing a flickering page in which each item comes one by one.

    This is the only best solution for whole application. See the code to put in the main form:

    protected override CreateParams CreateParams {
      get {
        CreateParams cp = base.CreateParams;
        cp.ExStyle |= 0x02000000;  // Turn on WS_EX_COMPOSITED
        return cp;
      }
    } 
    
    0 讨论(0)
  • 2020-11-22 02:50

    Try BeginUpdate/EndUpdate OR SuspendLayout/ResumeLayout methods. See following
    How to fix nested winform control flicker issues
    Flickering during updates to Controls in WinForms (e.g. DataGridView)

    0 讨论(0)
  • 2020-11-22 02:54

    It is not the kind of flicker that double-buffering can solve. Nor BeginUpdate or SuspendLayout. You've got too many controls, the BackgroundImage can make it a lot worse.

    It starts when the UserControl paints itself. It draws the BackgroundImage, leaving holes where the child control windows go. Each child control then gets a message to paint itself, they'll fill in the hole with their window content. When you have a lot of controls, those holes are visible to the user for a while. They are normally white, contrasting badly with the BackgroundImage when it is dark. Or they can be black if the form has its Opacity or TransparencyKey property set, contrasting badly with just about anything.

    This is a pretty fundamental limitation of Windows Forms, it is stuck with the way Windows renders windows. Fixed by WPF btw, it doesn't use windows for child controls. What you'd want is double-buffering the entire form, including the child controls. That's possible, check my code in this thread for the solution. It has side-effects though, and doesn't actually increase painting speed. The code is simple, paste this in your form (not the user control):

    protected override CreateParams CreateParams {
      get {
        CreateParams cp = base.CreateParams;
        cp.ExStyle |= 0x02000000;  // Turn on WS_EX_COMPOSITED
        return cp;
      }
    } 
    

    There are many things you can do to improve painting speed, to the point that the flicker isn't noticeable anymore. Start by tackling the BackgroundImage. They can be really expensive when the source image is large and needs to be shrunk to fit the control. Change the BackgroundImageLayout property to "Tile". If that gives a noticeable speed-up, go back to your painting program and resize the image to be a better match with the typical control size. Or write code in the UC's OnResize() method to create a properly sized copy of the image so that it doesn't have to be resized every time the control repaints. Use the Format32bppPArgb pixel format for that copy, it renders about 10 times faster than any other pixel format.

    Next thing you can do is prevent the holes from being so noticeable and contrasting badly with the image. You can turn off the WS_CLIPCHILDREN style flag for the UC, the flag that prevents the UC from painting in the area where the child controls go. Paste this code in the UserControl's code:

    protected override CreateParams CreateParams {
      get {
        var parms = base.CreateParams;
        parms.Style &= ~0x02000000;  // Turn off WS_CLIPCHILDREN
        return parms;
      }
    }
    

    The child controls will now paint themselves on top of the background image. You might still see them painting themselves one by one, but the ugly intermediate white or black hole won't be visible.

    Last but not least, reducing the number of child controls is always a good approach to solve slow painting problems. Override the UC's OnPaint() event and draw what is now shown in a child. Particular Label and PictureBox are very wasteful. Convenient for point and click but their light-weight alternative (drawing a string or an image) takes only a single line of code in your OnPaint() method.

    0 讨论(0)
  • 2020-11-22 02:55

    I tried to add this as a comment but I don't have enough points. This is the only thing that's ever helped my flickering problems so many thanks to Hans for his post. For anyone that's using c++ builder like myself here's the translation

    Add the CreateParams declaration to your application's main form .h file e.g.

    class TYourMainFrom : public TForm
    {
    protected:
        virtual void __fastcall CreateParams(TCreateParams &Params);
    }
    

    and add this to your .cpp file

    void __fastcall TYourMainForm::CreateParams(TCreateParams &Params)
    {
        Params.ExStyle |= 0x02000000;  // Turn on WS_EX_COMPOSITED
        TForm::CreateParams(Params);
    }
    
    0 讨论(0)
  • 2020-11-22 02:58

    If you are doing any custom painting in the control (i.e. overriding OnPaint) you can try the double buffering yourself.

    Image image;
    protected override OnPaint(...) {
        if (image == null || needRepaint) {
            image = new Bitmap(Width, Height);
            using (Graphics g = Graphics.FromImage(image)) {
                // do any painting in image instead of control
            }
            needRepaint = false;
        }
        e.Graphics.DrawImage(image, 0, 0);
    }
    

    And invalidate your control with a property NeedRepaint

    Otherwise the above answer with SuspendLayout and ResumeLayout is probably what you want.

    0 讨论(0)
提交回复
热议问题