Introduction
List and collection classes in the System.Collections namespace
have one disadvantage: they do not support events for common tasks. Of course, I am not saying they should. I am well aware of the performance issues, etc. However, in everyday life when the size of our lists takes about 10-100 items, performance is not so important. So, events. I have written a nice class, EventyList
, which has events for common methods such as Add
, AddRange
, Remove
, RemoveRange
, RemoveAt
, get
/set
accessors, Clear
and Insert
.
All of these events have two versions: "Before" and "On", e.g. BeforeAdd
and OnAdd
. "Before" events are called before the given action is performed, but after any error checking. I mean that they fire "just before". They also have a "Cancel" field and so, for example, the Add
method can be conditionally cancelled using the BeforeAdd
event. BeforeAdd
would pass the following arguments: EventyList
, the item to add and "ref cancel".
Prerequisites
This article assumes that you know something about events. If you do not, I recommend the article written by AbhishekKhanna: Unravelling Delegates & Events. If you do not wish to have complete knowledge about delegates and events, but you are interested in using my class, please read the rest of this section.
The Event term is very intuitive. When an "event" happens, a signal is sent to all of its listeners. To become a listener of an event, you have to "handle" it using accurate syntax. There must be a specified method (procedure) that has to be executed when an event "fires". To handle events of EventyList
or any other class, just write:
EventyList<int> myList = new EventyList<int>();
void Form1_Load()
{
myList.OnAdd += new EventyList<int>.EventyListAfterEventHandler(
myList_OnAdd);
myList.Add(123);
}
void myList_OnAdd(EventyList sender, int item)
{
MessageBox.Show("OnAdd fired!");
}
I am sorry to say this, but I do not have VB installed. So, I cannot provide a suitable code sample for this language. This is actually everything that is needed, however.
Source Code
The list implementation itself is identical to that of Microsoft. I have copied the source code of System.Collections.Generic.List<T>
to my class and then modified it for my usage. If you wonder where I got the MsCorLib
source from, you can download it from the Shared Source Common Language Infrastructure 2.0 Release: Download Details or browse for it at Rotor BCL Documentation.
Using the Code
Well, the usage is the same as List's usage. Here we go:
using Gajatko.Common;
using System.Windows.Forms;
void EventyTest()
{
EventyList<string> eve = new EventyList<string>();
eve.OnAction += eve_OnAction;
eve.BeforeAdd += eve_BeforeAdd;
eve.Add("Hello World");
eve.Add("Hello Dog");
eve.Add("Hello Chuck Norris");
string summary = eve[0];
for (int i = 1; i < eve.Count; i++)
{
summary += ", " + eve[i];
}
MessageBox.Show("Summary:" + Environment.NewLine + summary, "Summary",
MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
}
void eve_BeforeAdd(EventyList<string> sender,
ref string item, ref bool cancel)
{
if (item.Contains("Norris"))
{
MessageBox.Show(
"Cannot add item: \"" + item + "\". Personal data protection works!",
"Access denied.", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
cancel = true;
}
if (item.Contains("Dog"))
{
MessageBox.Show("We do not like dogs", "Animal refusal.",
MessageBoxButtons.OK,
MessageBoxIcon.Exclamation);
item = item.Replace("Dog", "Cat");
}
}
void eve_OnAction(EventyList<string> sender,
EventyList<string />.ActionEventArgs e)
{
if (e.Action == EventyList<string>.ListAction.Add)
MessageBox.Show("The item \"" + e.Item + "\" was successfully added.",
"Eventy message", MessageBoxButtons.OK,
MessageBoxIcon.Exclamation);
}
As you can see, it's nothing special, but it works fine anyway.
Extending EventyList Class
All event raisers are marked as virtual, which makes extending the class very simple, even without modifying the original code. The following example shows how to make a list of integers that ignores all Add
method calls. It also adds -1
after each AddRange
invocation.
public class IntegerEventyList : EventyList<int>
{
protected override bool beforeAdd(ref int item)
{
return false;
}
protected override void onAddRange(IEnumerable<int> coll)
{
base.onAddRange(coll);
Add(-1);
}
}
After operations, the list shown below...
IntegerEventyList list = new IntegerEventyList();
list.AddRange(new int[] {0, 556, 23, 88});
list.Add(5);
list.AddRange(new int[] { });
... would contain the following items:
0
556
23
88
-1
-1
Download
There is a source file available for download, eventylist.cs, as well as a compiled library, eventylist.dll. You can include the source file or DLL in your project. However, I recommend that you include only eventylist.cs instead of the DLL. Please inform me about any bugs found.
History
- 4th July, 2007 -- Original version posted
- 9th July, 2007 -- Improved thread safety and some other things
- 25th April, 2008 -- Updated download files