Michael Gillson

Share ideas, observations, expertise  
Using C# and the .NET Frame Work.

Event Handler

       The other day, an application needed an event handler. An appropriate delegate was created and it worked great. But I wanted to determine what the best practices are for event handlers. For instance, a click event for a button is defined in the designer as  

this.btnTest.Click += new System.EventHandler(this.btnTest_Click);
 
If the += is replaced with =, a compiler error is generated. The event 'MyEvent' can only appear on the left hand side of += or -=. My events need to have the same compiler protection. The generic class EventHandler<T> is an exact fit with my needs.
 
First, derive the custom event handler arguments from EventArgs and then connect the event to a class property.
 
public class DataChangeEventArgs : EventArgs
{
   public bool DataChanged { get; private set; }
 
   public DataChangeEventArgs(bool dataChanged)
      : base()
   {
     DataChanged = dataChanged;
  }
}
 
public event EventHandler<DataChangeEventArgs> DataChange = null;
protected void OnDataChange(DataChangeEventArgs e)
{
   // Microsoft suggests copying the variable to a temporary variable
   // to be thread safe.
   EventHandler<DataChangeEventArgs> tempEvent = DataChange;
   if (tempEvent != null)
      tempEvent(this, e);
}
 
private bool _DataChanged = false;
public bool DataChanged
{
   get { return _DataChanged; }
   set
   {
      if (value != _DataChanged)
      {
         _DataChanged = value;
         OnDataChange(new DataChangeEventArgs(value));
      }
   }
}
 
The class is simple with three data properties, FirstName, LastName and Age. FirstName is shown below. The other properties are pretty much the same.
 
private string _FirstName = string.Empty;
public string FirstName
{
   get { return _FirstName; }
   set
   {
      if (value == null)
         value = string.Empty;
      if (value != _FirstName)
      {
         _FirstName = value;
         DataChanged = true;
      }
   }
}
 
The following code tests the event handler and all works as expected.
 
static void Main(string[] args)
{
   Console.WriteLine();
   Simple item1 = new Simple()
   {
      FirstName = "Dave",
      LastName = "Jones",
      Age = 25,
      DataChanged = false
   };
 
   item1.DataChange += TestHandlerA;
   item1.DataChange += TestHandlerC;
   Console.WriteLine(" Changing Age - Expect Handlers A,C");
   item1.Age = 35;
 
   item1.DataChange -= TestHandlerC;
   item1.DataChange += TestHandlerB;
   item1.DataChange += TestHandlerB;
   item1.DataChange += TestHandlerB;
   Console.WriteLine(" Changing Last Name - Expect no handlers to be fired");
   item1.LastName = "Jackson";
 
   Console.WriteLine(" Reseting DataChanged - Expect Handlers A and B three times");
   item1.DataChanged = false;
 
   item1.DataChange -= TestHandlerB;
   Console.WriteLine(" Changing First Name - Expect Handlers A and B twice");
   item1.LastName = "Bill";
 
   item1.DataChangeClearAll(TestHandlerB);
   Console.WriteLine(" Reseting DataChanged - Expect Handler A");
   item1.DataChanged = false;        
 
   Console.ReadLine();
}
 
private static void TestHandlerA(object sender, Simple.DataChangeEventArgs e)
{
   Console.WriteLine(" A Handler, e.DataChanged = {0}",e.DataChanged);
}
 
 
 Changing Age - Expect Handlers A,C
 A Handler, e.DataChanged = True
 C Handler, e.DataChanged = True
 Changing Last Name - Expect no handlers to be fired
 Reseting DataChanged - Expect Handlers A and B three times
 A Handler, e.DataChanged = False
 B Handler, e.DataChanged = False
 B Handler, e.DataChanged = False
 B Handler, e.DataChanged = False
 Changing First Name - Expect Handlers A and B twice
 A Handler, e.DataChanged = True
 B Handler, e.DataChanged = True
 B Handler, e.DataChanged = True
 Reseting DataChanged - Expect Handler A
 A Handler, e.DataChanged = False
 
In the code above, DataChangeClearAll is highlighted. In my test, TestHandlerB is added three times. Normally, once is enough but maybe it gets added to the event property through indirect means like a DatGridView. The highlighted method shows a way to remove multiple copies of an event handler from the property. The parameter less version removes all handlers. This could be unwise code. I do not recommend it unless there is a very good reason to do it.
 
public void DataChangeClearAll(EventHandler<DataChangeEventArgs> clearEvent)
{
   if ((DataChange != null) && (clearEvent != null))
   {
      int removeCount = 0;
      foreach (Delegate item in DataChange.GetInvocationList())
         if (Object.Equals(clearEvent, item))
            removeCount++;
 
      int i = 0;
      while (i++ < removeCount)
         DataChange -= clearEvent;
   }
}
 
public void DataChangeClearAll()
{
   DataChange = null;
}
 

Download source files - 6.5 Kb


Site Map Printable View powered by mojoPortal Content Management System Valid XHTML 1.0 Transitional Valid CSS Design by Pax Armonia