1

I have been searching for a way to reduce the irritating flicker on my controls when opening a form for a while and the only solution I have found that works is using this Extended Window Style WS_EX_COMPSITED from the below documentation: https://learn.microsoft.com/en-us/windows/win32/winmsg/extended-window-styles

Protected Overrides ReadOnly Property CreateParams() As CreateParams   
    Get   
        Dim cp As CreateParams = MyBase.CreateParams   
        cp.ExStyle = cp.ExStyle Or &H2000000   
        Return cp   
    End Get   
End Property  

Adding this onto the class stops the controls flickering perfectly (albeit with a slight reduction in performance, but it's negligible in my case) - most likely because of the double-buffered form.

My problem is that when this Property is applied to the class, Graphics and Drawing seem to stop working in any capacity in the Class. I have tried the below code with the property added and removed, and it only works when it's removed:

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    Dim myPen As Pen
    Dim myBrush As Brush

    myPen = New Pen(Drawing.Color.FromArgb(53, 64, 82), 1)
    myBrush = New SolidBrush(Color.FromArgb(180, 204, 112))
    Dim myGraphics As Graphics = Me.Panel1.CreateGraphics
    myGraphics.DrawEllipse(myPen, 28, 28, 12, 12)
    myGraphics.FillEllipse(myBrush, 28, 28, 12, 12)
End Sub

I assume this has something to do with the way the WS_EX_COMPOSITED style works in terms of not refreshing/repainting correctly etc, but Me.Refresh() or Me.Panel1.Refresh() doesn't seem to repaint it in anyway.

Is there a workaround for this that I can use? Is this a bug or is this a limitation of this particular Extended Window Style?

ItsPete
  • 2,363
  • 3
  • 27
  • 35
RazorKillBen
  • 561
  • 2
  • 20
  • 4
    Do not EVER call `CreateGraphics`. Examples do it only for simplicity. If you want to draw on a control then handle the `Paint` event of that control and use the `Graphics` object provided. Also, be sure to dispose any objects that you create that support it, which includes `Pen` and `Brush` objects. Create them with a `Using` statement so that they are implicitly disposed when you're done with them. – jmcilhinney Jan 30 '20 at 23:21
  • `DoubleBuffer` the controls. Start with the containers. –  Jan 30 '20 at 23:29
  • 2
    The `Panel` class doesn't enable Double Buffering on its own. You should use a custom control (derived from Panel) to enable it. Maybe use a flat Label or a Picturebox, which have it enabled by default (the former is *lighter*). And, of course, use the Paint event to draw on a Control's surface. After that, you don't need the Composited style anymore (which, btw, if you handle that way, will disappear after you have minimized or maximized the Form) – Jimi Jan 30 '20 at 23:36
  • 1
    `Refresh` does repaint the control, which is also a reason why you don't see the graphics. Anything drawn with `CreateGraphics` is temporary and lasts only until the next time the control is redrawn. Redraw occurs for instance when the control is resized, when the form is minimized and maximized, when `Refresh` is called or when something changes in front of it, to mention a few cases. – Visual Vincent Jan 31 '20 at 09:15
  • Unfortunately @JQSOFT and @Jimi, I have tried double buffering the controls, and even created a custom `DoubleBufferedPanel` control, all of which do not stop the flickering. This occurs on all controls, including a PictureBox which I believe is set to DoubleBuffer by default. It lasts fractionally, but essentially when the form is Shown, a transparent 'hole' where the control should be is shown for around half a second until it loads the control. This occurs even on the most basic of forms. – RazorKillBen Jan 31 '20 at 10:58
  • Thanks @jmcilhinney - this is really useful to know, especially as the code I provided was dragged off of an example just to demonstrate the issue. Do you have a link possible to how I would re-write this using the `Paint` event? I wonder if doing this would actually fix the issue, based on the fact that `CreateGraphics` is a temporary object? – RazorKillBen Jan 31 '20 at 11:00
  • 1
    As all the values you're using are constant, just move the code to the Paint event handler of the control you want to draw on and use e.Graphics instead of that call to CreateGraphics. Don't forget to dispose your Pen and Brush. – jmcilhinney Jan 31 '20 at 11:54
  • Handle the `Paint` event of the `Panel1` control to do the drawing. Use the `e.Graphics` object to fill and draw the ellipse. And as already mentioned, dispose the disposable objects or declare them in `Using ... End Using` block. –  Jan 31 '20 at 13:36
  • 1
    Thanks @jmcilhinney and JQSOFT - really useful stuff. I'm hoping that this allows the two to run concurrently so will report back. Useful none-the-less. – RazorKillBen Jan 31 '20 at 15:23
  • Really appreciate this help - I can confirm that moving this to the `Paint` event and not using `CreateGraphics` did allow me to draw the graphic on the PictureBox with the property set. Really appreciate this useful piece of knowledge - if you'd like to submit it as an answer @jmcilhinney I'll accept. Thanks again and @JQSOFT – RazorKillBen Feb 01 '20 at 15:58
  • Most welcome mate. Good luck. –  Feb 01 '20 at 18:46
  • 2
    I'm happy for you to write your own answer based on your final solution. – jmcilhinney Feb 02 '20 at 02:14

0 Answers0