I'll do the fish and explain why you are having this problem. You are doing battle with a system option that's turned on for all modern Windows versions, named "Show window contents while dragging". That enables an optimization that minimizes the amount of painting that needs to be done when the user scrolls a window.
The basic way it works is that Windows itself scrolls the majority of the window content by the scroll amount by copying the pixels in the window. A fast bitblt that avoids having to repaint those pixels. The underlying winapi function is ScrollWindowEx(). And then invalidates the part of the window for which it doesn't have pixels to copy, just the bottom of the window if you scroll down, the top sliver if you scroll up. Accordingly, the app has to do much less work in its paint event handler, it only needs to draw the part of the window that was revealed by the scroll.
This plays havoc on the text that you draw in your OnPaint() method. It gets scrolled as well by the bitblt. But you don't scroll it yourself, you draw it in the same position regardless of the scrollbar position. The net effect is that the text "smears", the pixels of the text got moved but they are not being redrawn.
What you should do is scroll the text as well. Easy to do, your OnPaint() method override should look like this:
Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)
MyBase.OnPaint(e)
If Me.Text IsNot Nothing Then
e.Graphics.TranslateTransform(Me.AutoScrollPosition.X, Me.AutoScrollPosition.Y)
// etc, be sure to use e.Graphics
//...
End If
End Sub
The Graphics.TranslateTransform() call ensures that the text is offset properly and scrolls along with the rest of the pixels in the window. And the optimized bitblt will no longer cause the smearing.
This is what you should do but probably not what you want to do. Lars showed you a workaround, you have to intentionally defeat the optimization and force the entire window to be repainted, not just the optimized sliver that was revealed by the scroll.
That works, but it certainly does produce a visible artifact. For a brief moment, you'll see the scrolled text pixels, just before they get overpainted by OnPaintBackground(). The effect is, erm, interesting, you see it doing the "pogo", jumping up and down as you scroll.
A real fix requires disabling the bitblt optimization. User Tom showed how to do that in this answer. Works well on a Panel control as well, I'll reproduce his code in VB.NET syntax. Paste this code into your class:
Protected Overrides Sub WndProc(ByRef m As Message)
'' Trap scroll notifications, send WM_SETREDRAW
If m.Msg = 276 Or m.Msg = 277 Then
SendMessageW(Me.Handle, 11, IntPtr.Zero, IntPtr.Zero)
MyBase.WndProc(m)
SendMessageW(Me.Handle, 11, New IntPtr(1), IntPtr.Zero)
Me.Invalidate()
Return
End If
MyBase.WndProc(m)
End Sub
Private Declare Function SendMessageW Lib "User32.dll" (ByVal hWnd As IntPtr, ByVal Msg As Integer, ByVal WParam As IntPtr, ByVal LParam As IntPtr) As IntPtr