Something you see all the time in Javascript is using the flash and fade of the background color of an object to indicate some form of activity - success, error, etc. There is nothing that makes this easy in C#, but I managed to do it using some hacky Invoke calls.
Code is after the break, but you can download the entire test project: ColorAnim Test Project (VS2005)

Code:


using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.ComponentModel;
using System.Reflection;

namespace ColorAnim
{
class ColorAnim
{
private Dictionary colorsFading = new Dictionary();
private Dictionary backgroundWorkers = new Dictionary();
// The delegate of a method that will be called when the color finishes fading
public delegate void DoneFading(Object container,String colorProperty);

public struct ColorStep
{
private Color _color;
public Color Color
{
get { return _color;}
set { _color = value;}
}

private int _steps;

public int Steps
{
get { return _steps;}
set { _steps = value;}
}
public ColorStep(Color color,int steps)
{
this._color = color;
this._steps = steps;
}
}

private class ColorFaderInformation
{
private DoneFading _callback;

public DoneFading CallBack
{
get { return _callback; }
set { _callback = value; }
}
private Object _container;

public Object Container
{
get { return _container; }
set { _container = value; }
}
private String _colorProperty;

public String ColorProperty
{
get { return _colorProperty; }
set { _colorProperty = value; }
}
private Color _startColor;

public Color StartColor
{
get { return _startColor; }
set { _startColor = value; }
}
private IEnumerable _colors;

public IEnumerable Colors
{
get { return _colors; }
set { _colors = value; }
}
private int _delay;

public int Delay
{
get { return _delay; }
set { _delay = value; }
}
private bool _rerun;

public bool Rerun
{
get { return _rerun; }
set { _rerun = value; }
}
public ColorFaderInformation(Object container, String colorProperty, Color startColor, IEnumerable colorSteps, int delay, DoneFading callback)
{
this._container = container;
this._colorProperty = colorProperty;
this._startColor = startColor;
this._colors = colorSteps;
this._delay = delay;
this._callback = callback;
this._rerun = false;
}
}

private string GenerateHashCode(Object container, string colorProperty)
{
return container.GetHashCode() + colorProperty;
}

private void BackgroundWorker_RunWorkerCompleted(Object sender,RunWorkerCompletedEventArgs e)
{
ColorFaderInformation info;
if(backgroundWorkers.TryGetValue((BackgroundWorker)sender,out info))
{
if(!e.Cancelled)
{
if(info.CallBack != null)
{
info.CallBack.Invoke(info.Container,info.ColorProperty);
}
backgroundWorkers.Remove((BackgroundWorker)sender);
colorsFading.Remove(GenerateHashCode(info.Container,info.ColorProperty));
}
else
{
if(info.Rerun)
{
info.Rerun = false;
((BackgroundWorker)sender).RunWorkerAsync(info);
}
}
}
}

private void BackgroundWorker_ProgressChanged(Object sender,ProgressChangedEventArgs e)
{
ColorFaderInformation info;
if (backgroundWorkers.TryGetValue((BackgroundWorker)sender, out info))
{
Color currentColor = (Color)e.UserState;
try
{
PropertyInfo prop = (info.Container.GetType()).GetProperty(info.ColorProperty);
MethodInfo method = prop.GetSetMethod(true);
method.Invoke (info.Container, new object[]{currentColor});
}
catch(Exception ex)
{
System.Diagnostics.Debug.Write(ex.ToString());
}
}
}

private void BackgroundWorker_DoWork(Object sender,DoWorkEventArgs e)
{
ColorFaderInformation info = (ColorFaderInformation)e.Argument;
double curR;
double curG;
double curB;
Color startStepColor = info.StartColor;
Color endStepColor;
foreach(ColorStep colorStep in info.Colors)
{
endStepColor = colorStep.Color;
// Gets the amount to change each color part per step
double rStep = ((double)endStepColor.R - startStepColor.R) / colorStep.Steps;
double gStep = ((double)endStepColor.G - startStepColor.G) / colorStep.Steps;
double bStep = ((double)endStepColor.B - startStepColor.B) / colorStep.Steps;

// The red, green and blue parts og the current color
curR = startStepColor.R;
curG = startStepColor.G;
curB = startStepColor.B;

for(int i=1;i {
curR += rStep;
curB += bStep;
curG += gStep;
((BackgroundWorker)sender).ReportProgress(0,Color.FromArgb((int)curR,(int)curG,(int)curB));
System.Threading.Thread.Sleep(info.Delay);
if(((BackgroundWorker)sender).CancellationPending)
{
e.Cancel = true;
break;
}
}
startStepColor = endStepColor;
}

}

private void inColorAnim (Object container,String colorProperty,Color startColor,IEnumerable colorSteps,int delay,DoneFading callback)
{
BackgroundWorker colorFader;
ColorFaderInformation colorFaderInfo = new ColorFaderInformation(container,colorProperty,startColor,colorSteps,delay,callback);
if(colorsFading.TryGetValue(GenerateHashCode(container,colorProperty),out colorFader))
{
colorFader.CancelAsync();
colorFaderInfo.Rerun = true;
backgroundWorkers[colorFader] = colorFaderInfo;
}
else
{
colorFader = new BackgroundWorker();
colorFader.DoWork += new DoWorkEventHandler(BackgroundWorker_DoWork);
colorFader.ProgressChanged += new ProgressChangedEventHandler(BackgroundWorker_ProgressChanged);
colorFader.RunWorkerCompleted += new RunWorkerCompletedEventHandler(BackgroundWorker_RunWorkerCompleted);
colorFader.WorkerReportsProgress = true;
colorFader.WorkerSupportsCancellation = true;
backgroundWorkers.Add(colorFader,colorFaderInfo);
colorsFading.Add(GenerateHashCode(container,colorProperty), colorFader);
}
if(!colorFader.IsBusy)
{
colorFader.RunWorkerAsync(colorFaderInfo);
}
}

public ColorAnim(Object container, String colorProperty, Color startColor, Color middleColor, int middleSteps, Color endColor, int endSteps, int delay, DoneFading callback)
{
ColorStep[] colorSteps = new ColorStep[2];
colorSteps[0] = new ColorStep(middleColor,middleSteps);
colorSteps[1] = new ColorStep(endColor,endSteps);
this.inColorAnim(container,colorProperty,startColor,colorSteps,delay,callback);
}

public ColorAnim(Object container,String colorProperty,Color startColor,Color endColor,int steps,int delay, DoneFading callback)
{
ColorStep[] colorSteps = new ColorStep[1];
colorSteps[0] = new ColorStep(endColor,steps);
this.inColorAnim(container, colorProperty, startColor, colorSteps, delay, callback);
}
}
}

And you call it with just one line of code:

ColorAnim ca = new ColorAnim(textBox1, “BackColor”, Color.White, textBox1.BackColor, 100, 5, null);

Have fun!