Over the past couple of weeks I’ve been working a data validation framework. As part of this development effort I needed to listen to the events raised by DataTable instances in order to trigger automatic background validation. This validation would involve spinning through rows in the data-table and arriving at a result, flagging any errors along the way.
Unfortunately I started having problems when rows were added to the data-table and the RowChanged event got fired. You see, the RowChanged event fires BEFORE the data-table has the row added to it – I think that is kind of counter intuitive. Now its probably a bit late to change the .NET framework now, especially since there is probably a bit of code out there that relies of this behaviour, but I would like to see the addition of a number of events – like RowAdded, which only fires AFTER the data-row is accessible.
So, how did I work around it? Well, since this is really proof of concept code I had some scope to implement a bit of a dirty hack, and it goes like this.
public void InjectHack(DataTable dt)
{
DataRowCollection collection = dt.Rows;
Type collectionType = collection.GetType();
FieldInfo fi = collectionType.GetField(
“list”,
BindingFlags.Instance | BindingFlags.NonPublic
);
ArrayList list = (ArrayList)fi.GetValue(collection);
WrapperArrayList wrapperList = new WrapperArrayList(list);
wrapperList.ItemAdded += new EventHandler(wrapperList_ItemAdded);
fi.SetField(collection, wrapperList);
}
private void wrapperList_ItemAdded(object sender, EventArgs e)
{
// Put the code you would expect to be able to
// have in a handler for the RowChanged event.
}
// Filename: WrapperArrayList.cs
public class WrapperArrayList
{
public WrapperArrayList(ArrayList list)
{
this.AddRange(list);
}
public override int Add(object value)
{
int index = base.Add(value);
this.OnItemAdded(new EventArgs());
return index;
}
public event EventHandler ItemAdded;
protected void OnItemAdded(EventArgs e)
{
if (this.ItemAdded != null)
{
this.ItemAdded(this, e);
}
}
}
See what I mean by hack? It does work though, there are a few other ways to tackle this but they are all pretty hacky, and this is the one that I settled for. What it does is use reflection to grab the internal ArrayList that the DataRowCollection uses to store data-rows and replaces it with an instance of an ArrayList-derived class which overrides the Add method and raises an event at the right time.
I’d love to hear your ideas around a better way to do this.