Click here to Skip to main content
Click here to Skip to main content

EventyList: The List with Events

, 28 Apr 2008
Rate this:
Please Sign up or sign in to vote.
Generic list class based on Microsoft's implementation with few additional events to handle like BeforeAdd, OnAdd, BeforeRemove, etc.

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:

// C#
// First declare and initialize EventyList somewhere
EventyList<int> myList = new EventyList<int>();

// Inside some method...
void Form1_Load()
{
    // ... handle an event this way:
    myList.OnAdd += new EventyList<int>.EventyListAfterEventHandler(
        myList_OnAdd);
    // (if you input "myList.OnAdd +=", Visual Studio will tell
    // you that you can press TAB - just do it.

    // Raise "OnAdd" by adding an item:
    myList.Add(123);

    // In C# 2.0 (Visual Studio 2005), you could also
    // write the same thing this way:
    // myList.OnAdd += myList_OnAdd;
    // (As we can read in C# specification: "C# compiler has
    // enough context to determine... blah blah")
}

// When OnAdd fires, this method will be executed
void myList_OnAdd(EventyList<int /> 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:

// C#
// Add these to a header of your source file
using Gajatko.Common;
using System.Windows.Forms;

void EventyTest()
{
    // Declare EventyList
    EventyList<string> eve = new EventyList<string>();

    // Handle events
    eve.OnAction += eve_OnAction;
    eve.BeforeAdd += eve_BeforeAdd;
    // (Now look at eve_BeforeAdd and eve_OnAction below)
    // Of course there is an OnAdd event, but I want to
    // show how OnAction works

    // Add items
    eve.Add("Hello World");
    eve.Add("Hello Dog");
    eve.Add("Hello Chuck Norris");

    // Construct summary
    string summary = eve[0];
    for (int i = 1; i < eve.Count; i++)
    {
        summary += ", " + eve[i];
    }

    // Display summary in msgbox
    MessageBox.Show("Summary:" + Environment.NewLine + summary, "Summary",
    MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
}

void eve_BeforeAdd(EventyList<string> sender,
    ref string item, ref bool cancel)
{
    // Do some validation of items.
    if (item.Contains("Norris"))
    {
        MessageBox.Show(
        "Cannot add item: \"" + item + "\". Personal data protection works!",
        "Access denied.", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);

        // Prohibit Norris.
        cancel = true;
    }
    if (item.Contains("Dog"))
    {
        MessageBox.Show("We do not like dogs", "Animal refusal.",
            MessageBoxButtons.OK,
            MessageBoxIcon.Exclamation);

        // Replace all dogs in the world with cats. Note that
        // we can modify data.
        item = item.Replace("Dog", "Cat");
    }
}

void eve_OnAction(EventyList<string> sender,
    EventyList<string />.ActionEventArgs e)
{
    // This is an OnAction demo - OnAction events fires always AFTER the
    // specialized one does.
    // Unfortunately, "BeforeAction" does not support changing data - only
    // cancelling is possible.
    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

License

This article, along with any associated source code and files, is licensed under The GNU General Public License (GPLv3)

Share

About the Author

Jacek Gajek
Software Developer (Junior)
Poland Poland
My name is Jacek Gajek. I have graduated in computer science with a master's degree from Polibuda in Wrocław. I like C# and Monthy Python's sense of humour.

Comments and Discussions

 
Questionwindows events PinmemberMokhtar abdualmomien22-Jan-11 12:18 
AnswerRe: windows events PinmemberJacek Gajek22-Jan-11 22:24 
GeneralBug Found!! PinmemberMember 223039725-Apr-08 0:24 
GeneralRe: Bug Found!! Pinmembergajatko25-Apr-08 6:20 
GeneralBeware the license! Pinmemberggeurts12-Jul-07 14:19 
GeneralRe: Beware the license! Pinmembergajatko13-Jul-07 3:30 
QuestionWhy not C5? Pinmembergerektoolhy11-Jul-07 20:56 
AnswerRe: Why not C5? [modified] Pinmembergajatko12-Jul-07 0:19 
GeneralRe: Why not C5? Pinmembergerektoolhy12-Jul-07 4:31 
GeneralRe: Why not C5? Pinmembergajatko12-Jul-07 4:57 
GeneralBindingList PinmemberRobert Ensor10-Jul-07 12:36 
GeneralRe: BindingList Pinmembergajatko11-Jul-07 0:17 
GeneralUse the standard EventHandler signature PinmemberObiwan Jacobi10-Jul-07 1:59 
GeneralRe: Use the standard EventHandler signature Pinmembergajatko10-Jul-07 3:30 
GeneralMulti-threading Pinmembermcarbenay4-Jul-07 6:03 
GeneralRe: Multi-threading Pinmembergajatko4-Jul-07 23:40 
GeneralRe: Multi-threading PinmemberObiwan Jacobi10-Jul-07 1:56 
GeneralRe: Multi-threading Pinmembermcarbenay10-Jul-07 12:32 
GeneralRe: Multi-threading Pinmembergajatko11-Jul-07 0:26 
GeneralRe: Multi-threading Pinmembermcarbenay11-Jul-07 2:16 
GeneralRe: Multi-threading PinmemberDjeez19-Jul-07 8:28 
GeneralGood job, but a question PinmemberFrederic Sivignon4-Jul-07 5:55 
GeneralRe: Good job, but a question PinmemberKellyLeahy4-Jul-07 7:58 
GeneralRe: Good job, but a question Pinmembergajatko4-Jul-07 23:48 
GeneralRe: Good job, but a question Pinmembergajatko5-Jul-07 4:26 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web01 | 2.8.140902.1 | Last Updated 28 Apr 2008
Article Copyright 2007 by Jacek Gajek
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid