/// <summary> /// Raises the <see cref="E:System.Windows.Forms.Control.Paint" /> event. /// </summary> /// <param name="e">A <see cref="T:System.Windows.Forms.PaintEventArgs" /> that contains the event data.</param> protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); if (BufferedPaintSupported) { bool stateChanged = !Object.Equals(currentState, newState); using (var hdc = new SafeGDIHandle(e.Graphics)) { if (!hdc.IsInvalid) { // see if this paint was generated by a soft-fade animation if (!NativeMethods.BufferedPaintRenderAnimation(this.Handle, hdc)) { NativeMethods.BufferedPaintAnimationParams animParams = new NativeMethods.BufferedPaintAnimationParams(NativeMethods.BufferedPaintAnimationStyle.Linear); // get appropriate animation time depending on state transition (or 0 if unchanged) if (stateChanged) { foreach (var item in transitions) { if (item.currentState == currentState && item.newState == newState) { animParams.Duration = item.duration; break; } } } Rectangle rc = this.ClientRectangle; IntPtr hdcFrom, hdcTo; IntPtr hbpAnimation = NativeMethods.BeginBufferedAnimation(this.Handle, hdc, ref rc, NativeMethods.BufferedPaintBufferFormat.CompatibleBitmap, IntPtr.Zero, ref animParams, out hdcFrom, out hdcTo); if (hbpAnimation != IntPtr.Zero) { if (hdcFrom != IntPtr.Zero) { using (Graphics gfxFrom = Graphics.FromHdc(hdcFrom)) PaintControl(new PaintEventArgs(gfxFrom, e.ClipRectangle)); } currentState = newState; if (hdcTo != IntPtr.Zero) { using (Graphics gfxTo = Graphics.FromHdc(hdcTo)) PaintControl(new PaintEventArgs(gfxTo, e.ClipRectangle)); } NativeMethods.EndBufferedAnimation(hbpAnimation, true); } else { hdc.Dispose(); currentState = newState; PaintControl(e); } } } } } else { // buffered painting not supported, just paint using the current state currentState = newState; PaintControl(e); } }