Last week I was working on an event handler to prevent users from changing a value of a custom list item one an external service is busy processing some data.
Reading some information on event handlers I learned some important aspects about event handlers.
Deploy to the GAC: the assembly containing the event handler must be deployed to the Global Assembly Cache.
-Ed en -Ing events (asynchronous and synchronous events)
Event names ending on –ed like ItemUpdated, ItemDeleted and so on are called asynchronous events as they will execute after the action has been completed. At this stage you can no longer prevent something from being save or deleted.
The events ending in “ing” like ItemUpdating, ItemInserting and so on fire before the action is completed and are therefore called synchronous. In this case you can still intervene before the action is final.
The full list of available methods that can be overridden for SPItemEventReceiver can be found in the following MSDN article: http://msdn2.microsoft.com/en-us/library/ms437502.aspx
DisableEventFiring()
If you need to do an update to an item from within your event receiver you might end up in a recurring event being fired for the updates. To prevent this you can call DisableEventFiring() and then EnableEventFiring(). A small example for this:
public override void ItemUpdated(SPItemEventProperties properties)
{
//some handling here
ListItem item = properties.ListItem;
item["someproperty"] = "some value";
this.DisableEventFiring();
//save changes
addedItem.Update();
this.EnableEventFiring();
}
When calling the Update method you might also consider using SystemUpdate() method which will do a SharePoint database updating without updating the time modified or versions of the item.
So now back to my event handler: I was looking for a way to know from within the event handler if it had been fired by a user action or by a system update. A system update is in my case a windows service opening the list item by using the object model.
As I’m using a schema.xml file to create the custom list I added a boolean field with the ReadOnly attribute set to true. This makes the custom field hidden in the edit form for the list item. When updating the item through the object model I do have access to the custom readonly field and can set its properties.
schema.xml snippet:
... ...
<Fields>
<Field ID="{1FFDF566-D220-45e0-814D-34DB0E1A253D}" Name="Myreadonlyfield" StaticName="Myreadonlyfield" SourceID="http://schemas.microsoft.com/sharepoint/v3" Group="Groupname" DisplayName="SystemUpdate" Description="Hidden system field" Type="Boolean" ReadOnly="TRUE" Sealed="TRUE"></Field>
</Fields>
...
</Fields>
My custom application sets the read only field to true before calling Update:
item["fieldx"] = “some update”;
item["SystemUpdate"] = true;
item.Update();
As I’m using a synchronous event handler I can change the AfterProperties before these are saved into the database. This prevents the field from having a “true” value next time the item is updated.
public override void ItemUpdating(SPItemEventProperties properties)
{
bool isServiceUpdate = false;
string modifiedStatus = Convert.ToString(properties.AfterProperties["somestatusfield"]);
isServiceUpdate = Convert.ToBoolean(properties.AfterProperties["Myreadonlyfield"]);
// Myreadonlyfield is always set to false except when the update comes from my custom application
if (isServiceUpdate == false)
{
if (modifiedStatus.ToLower() == "invalid")
{
properties.ErrorMessage = "This is an invalid choice...";
properties.Cancel = cancel;
}
}
else
{
properties.AfterProperties["Myreadonlyfield"] = false;
}
}
I’m thinking maybe there is a much more efficient way of doing this but as I did not find any this way my solution. And what counts is it does the work.
And then here is a fantastic article series I found recently with very good information about event handlers in SharePoint 2007:
Brian Wilson - Event Handlers - Part 1: Everything you need to know about Microsoft Office SharePoint Server (MOSS) Event Handlers.