Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

ColoredErrorProvider: Custom Extender Provider, based on ErrorProvider class.

0.00/5 (No votes)
21 Jan 2004 2  
Indicates error within the control by flashing the control's background color.

Sample Image - ColoredErrorProvider-pic.jpg

Introduction

The ColoredErrorProvider is a custom Extender Provider. Like the ErrorProvider component, this class can be used to warn the user of invalid data.

Extender Providers

An extender provider allows you to extend a control without creating additional classes.

ToolTip Extender Provider

The ToolTip control in .NET is an extender provider. Instead of each of the controls like buttons, labels, textboxes etc. having a ToolTip property, we can use the ToolTip class to set a tooltip for it as shown below:

   ToolTip toolTip1 = new ToolTip();
   toolTip1.SetToolTip(this.label1, "This is a label");
   toolTip1.SetToolTip(this.button1, "this is a button");

ErrorProvider Extender Provider

The ErrorProvider is a pretty neat control that allows you to display an error icon next to controls if the data in them is invalid. This is very convenient considering that the alternative would be to:

  1. pop up an error dialog
  2. show a status bar error
  3. allow verification to be handled during processing.

The class in this example is similar to the ErrorProvider class. What has been changed is that the error/warning is indicated to the user by flashing the control's background color. I wrote this because the icon I had to display using ErrorProvider could not be placed in any convenient location; the icon overlapped with some other control or went out of the bounds of the form. And of course, to learn how to write an Extender Provider.

Sample

The sample contains a small program with a few components that illustrate using this class. Clicking the "Toggle Error" button sets/unsets the errors on the controls in the groupbox. TextBox3 is validated. If it contains more than 10 chars, the error is set. Change the number of characters in this text field and take focus away from it to see the effect of the ColoredErrorProvider class.

Usage

While creating the ColoredErrorProvider, one can specify:

  • blinkCount: The number of times the control will blink before it settles on the settle color.
  • blinkInterval: The time in milliseconds between each blink.

While setting the error, one can specify:

  • control: The Control on which the error must be applied.
  • value: If it is not empty then the control will blink. If it is empty then it will not display the error. The string itself is NOT displayed to the user like ErrorProvider does.
  • blinkColor: The color that is the background color when the control blinks.
  • blinkCount: The number of times the control will blink before it settles on the settle color.
  • settleColor: The background color of the control when the blinking is over.

Code Walkthrough

Class Form1 is the example application form. I will not be walking you through this code.

The ColoredErrorProvider extends a Control and implements IExtenderProvider which is necessary to implement your own extender provider. MSDN says "Any component that provides extender properties must implement IExtenderProvider. A visual designer can then call CanExtend to determine which objects in a container should receive the extender properties". Since all derivatives of the Control class will have a BackColor property, we override the CanExtend method to return true if the object is a Control:

bool IExtenderProvider.CanExtend(object target)
{
  if (target is Control) 
  {
    return true;
  }
  return false;
}

In order to retain the different controls for which a ColoredError has been provided, I instantiated a HashTable. The key to the HashTable is the control and the value is a BlinkControlDetails structure that contains the details of the ColoredError associated with the control.

private Hashtable originalControlColors = new Hashtable();
struct BlinkControlDetails
{
  public Color OriginalBackColor;
  public Color BlinkBackColor;
  public Color SettleBackColor;
  public string ErrorString;
  private int[] BlinkCountArray;
  ...
}

The BlinkCountArray is a hack workaround. I didn't know how to change the value of a primitive type that is a member of a structure and which is returned as a key's value from the HashTable. If somebody would enlighten me about a better way to do this, it would be great. The BlinkCountArray contains only one entry. This is indirectly manipulated through the public property BlinkCount.

When SetError is called on the ColoredErrorProvider:

  • I check if the error is to be set or removed depending on the length. If it is to be removed then set the background color to the original color and then remove it from the HashTable.
  • If it is new, I create a new BlinkControlDetails with appropriate entries and add it to the HashTable. We also enable the timer so that we can make the control's back color blink.
public void SetError(Control control, 
  string value, Color blinkColor, int blinkCount, Color settleColor)
{
  if (value == null)
  {
    value = string.Empty;
  }
  
  if (value.Length == 0)
  {
    if (this.originalControlColors.ContainsKey(control))
    {
      control.BackColor = ((BlinkControlDetails)
        this.originalControlColors[control]).OriginalBackColor;
      this.originalControlColors.Remove(control);
    }
    control.Invalidate();
  }
  else
  {
    BlinkControlDetails bcd = new BlinkControlDetails(value, 
         control.BackColor, blinkColor, settleColor, blinkCount*2-1);
    this.originalControlColors.Add(control, bcd);
    control.BackColor = blinkColor;
    control.Invalidate();
    
    if (!this.timer.Enabled)
    {
      this.timer.Enabled = true;
    }
  }
}

When the class is created, I create an instance of a timer. The timer is enabled when SetError is called.

private Timer timer = new Timer();

When the timer ticks, it calls the method OnTimerTick.

private void OnTimerTick(Object myObject, EventArgs myEventArgs)
{
  bool atLeastOneBlinked = false;
  foreach (Control c in this.originalControlColors.Keys)
  {
    BlinkControlDetails bcd = 
       (BlinkControlDetails)this.originalControlColors[c];
    if (bcd.BlinkCount>=1)
    {
      if (c.BackColor.Equals(bcd.OriginalBackColor))
      {
        c.BackColor = bcd.BlinkBackColor;
      }
      else if (c.BackColor.Equals(bcd.BlinkBackColor))
      {
        c.BackColor = bcd.OriginalBackColor;
      }
      bcd.BlinkCount--;
      atLeastOneBlinked = true;
    }
    else if(bcd.BlinkCount==0)
    {
      c.BackColor = bcd.SettleBackColor;
      bcd.BlinkCount--;
      atLeastOneBlinked = true;
    }
    else
    {
      continue;
    }
    c.Invalidate();
  }
  if (!atLeastOneBlinked)
   {
     this.timer.Enabled = false;
   }
}

We loop through the controls in the HashTable which contains the controls onto which the error provider has been set. For each control, we flip the back color between the original back color and the blink back color. On each blink, we decrement the blink count. Once blink count has reached 0, we set the back color to the settleColor. The settle color will inform the user that there is a problem without disturbing him/her with the blinking.

Variable atLeastOneBlinked is set to true if there is at least one more control that has to blink. If there isn't, we can disable the timer.

Related Links

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here