public static void HandleWmPaint(ref Message m, Control control, Action <PaintEventArgs> paint) { var ps = new WinApi.PAINTSTRUCT(); bool needDisposeDc = false; try { Rectangle clip; IntPtr dc; if (m.WParam == IntPtr.Zero) { dc = WinApi.BeginPaint(new HandleRef(control, control.Handle), ref ps); if (dc == IntPtr.Zero) { return; } needDisposeDc = true; clip = new Rectangle(ps.rcPaint_left, ps.rcPaint_top, ps.rcPaint_right - ps.rcPaint_left, ps.rcPaint_bottom - ps.rcPaint_top); } else { dc = m.WParam; clip = control.ClientRectangle; } if (clip.Width > 0 && clip.Height > 0) { try { using (var bufferedGraphics = BufferedGraphicsManager.Current.Allocate(dc, control.ClientRectangle)) { bufferedGraphics.Graphics.SetClip(clip); using (var pevent = new PaintEventArgs(bufferedGraphics.Graphics, clip)) { paint?.Invoke(pevent); } bufferedGraphics.Render(); } } catch (Exception ex) { // BufferContext.Allocate will throw out of memory exceptions // when it fails to create a device dependent bitmap while trying to // get information about the device we are painting on. // That is not the same as a system running out of memory and there is a // very good chance that we can continue to paint successfully. We cannot // check whether double buffering is supported in this case, and we will disable it. // We could set a specific string when throwing the exception and check for it here // to distinguish between that case and real out of memory exceptions but we // see no reasons justifying the additional complexity. if (!(ex is OutOfMemoryException)) { throw; } } } } finally { if (needDisposeDc) { WinApi.EndPaint(new HandleRef(control, control.Handle), ref ps); } } }