So, I've written an image viewer that allows zooming, moving it around while zooming and Async-image loading to keep everything responsive. It works well with very little lag problems...except when I start displaying animated GIF images. In my program I store images in my own format, where all frames in the GIF are stored as bitmaps of ARGB32 (fastest format). A thread runs to increment the displayed frame and force a redraw using control.invalidate. Some excerpts:

Image frame is incremented, firing an (Async, not UI!) event handled by any listener (controls):
    Private Sub UpdateAnimation()
        Dim now As Date = Date.Now
        Dim lastFrameChange As Date = now
        While Not disposedValue AndAlso Not Me.m_animateThread.IsAborting
            now = Date.Now
            If now.Subtract(lastFrameChange).TotalMilliseconds >= Me.m_frameDelays(Me.m_frameIndex) Then
                lastFrameChange = now
                Me.CurrentFrame += 1
            End If
        End While
    End Sub
Which in turn...:
    Private Sub OnFrameChanged(ByVal sender As System.Object, ByVal e As System.EventArgs)
    End Sub
And then to redraw the image this is called by onPaint in the control the image is drawn in:
    Public Sub Draw(ByVal g As Graphics, ByVal interpolation As Drawing2D.InterpolationMode, ByVal screenSize As Size, ByVal Offset As Point, ByVal Zoom As Double)
        If Me.IsDisposed Then
        End If
        Dim srcRect As New RectangleF(0, 0, Me.Width, Me.Height)
        Dim destRect As New RectangleF(-Offset.X, -Offset.Y, Width * Zoom, Height * Zoom)

        ' Draw background gradient image if destRect does not cover the entire screen
        If destRect.Left > 0 OrElse destRect.Top > 0 OrElse destRect.Right < Me.Width OrElse destRect.Height < Me.Height Then
            If BackgroundImage.Width > 1 AndAlso BackgroundImage.Height > 1 Then
                Dim thumbSrcRect As New RectangleF(0.0F, 0.0F, BackgroundImage.Width - 1.0F, BackgroundImage.Height - 1.0F)
                g.InterpolationMode = Drawing2D.InterpolationMode.Low
                g.DrawImage(BackgroundImage, New RectangleF(0, 0, screenSize.Width, screenSize.Height), thumbSrcRect, GraphicsUnit.Pixel)
            End If
        End If

        ' Calculate the offset and zoom, and draw the image in the resulting rectangle
        If destRect.Left < 0 Then
            srcRect.X -= destRect.X / Zoom
            srcRect.Width -= srcRect.X
            destRect.Width += destRect.X
            destRect.X = 0
        End If
        If destRect.Top < 0 Then
            srcRect.Y -= destRect.Y / Zoom
            srcRect.Height -= srcRect.Y
            destRect.Height += destRect.Y
            destRect.Y = 0
        End If
        If destRect.Right > screenSize.Width Then
            srcRect.Width -= ((destRect.Right - screenSize.Width) / Zoom) - 1.0
            destRect.Width = (screenSize.Width - destRect.Left) + Zoom
        End If
        If destRect.Bottom > screenSize.Height Then
            srcRect.Height -= ((destRect.Bottom - screenSize.Height) / Zoom) - 1.0
            destRect.Height = (screenSize.Height - destRect.Top) + Zoom
        End If
        g.InterpolationMode = interpolation
        g.DrawImage(Image, destRect, srcRect, GraphicsUnit.Pixel)
    End Sub
This all works excellently. The image animates at the right speed. But there is one major problem: the continuous invalidation of the image displaying control causes all other menus and controls to redraw poorly or not at all. When hovering over buttons, they don't change state. When resizing the window the controls hardly redraw and glitch out. Similarly in menus they don't pop up or take very long to change state when hovering over a menu item. It gives the appearance that the program is unresponsive. I don't see this happening in webbrowsers and the like, and at the same time I am aware that you can not perform screen drawing on another thread. So what to do? What can I do to prevent the entire application from freezing all drawing operations? Is this a problem caused by 'Invalidate'?

Using a timer instead of a thread to routinely call invalidate during animation did not help.