Tuesday, June 17, 2014

SharePoint List Event Handler Types and Working with AfterProperties and BeforeProperties


Scenario:  I was having the requirement to execute my custom code when a SharePoint ListItem is updated.  This custom code should write some of the updated field values to database. My custom list consists of following fields:

TaskID, Task Name, Project Name,  Task Type, Cost, Work,  Reason For Change, Impact

When any listitem is updated, I need to check if the fields  Reason For Change or Impact have been changed. If these fields are changed then I need to update these field values in database also with my custom code.

Solution:
The List Event Handlers provide BeforeProperties and AfterProperties collection which should enable to compare original and edited field values and make decision when to execute the custom code.  If we do not compare the original and edited field values then the custom code will be executed every time the item is updated.

Before talking about the Properties, let me give a brief about type of Event Handlers. SharePoint 2010 offers 2 types of Event Handlers which we can attach to List, Libraries, etc. These are Synchronous and Asynchronous. The differences between these Event Handlers are:

Asynchronous
Synchronous
Executes after event is executed, these event handler methods end with ‘–ed’. For example ItemAdded, ItemUpdated, ItemDeleted
Executes before event occurs, these event handler methods end with ‘–ing’. For example ItemAdding, ItemUpdating, ItemDeleting
These event handlers are used when certain code is required to be executed after event occurs. These event handlers cannot stop/cancel the event execution.
These event handlers are mostly used when the execution of event is based on some condition. We can write the code to execute the event only when certain condition is true else we can stop the event execution.

 In the above case, as execution of custom code was based upon comparison of field values so I am running my code under the ItemUpdating event handler method.
 
 
values then the custom code will be executed every time the item is updated.
Before talking about the Properties, let me give a brief about type of Event Handlers. SharePoint 2010 offers 2 types of Event Handlers which we can attach to List, Libraries, etc. These are Synchronous and Asynchronous. The differences between these Event Handlers are:
Asynchronous
Synchronous
Executes after event is executed, these event handler methods end with ‘–ed’. For example ItemAdded, ItemUpdated, ItemDeleted
Executes before event occurs, these event handler methods end with ‘–ing’. For example ItemAdding, ItemUpdating, ItemDeleting
These event handlers are used when certain code is required to be executed after event occurs. These event handlers cannot stop/cancel the event execution.
These event handlers are mostly used when the execution of event is based on some condition. We can write the code to execute the event only when certain condition is true else we can stop the event execution.
 
In the above case, as execution of custom code was based upon comparison of field values so I am running my code under the ItemUpdating event handler method.
Now, the event handler method provides the SPItemEventProperties properties object which provides three ways to access the field values:
-          properties.ListItem[FieldName]
-          properties.AfterProperties
-          properties.BeforeProperties
The link Working with BeforeProperties and AfterProperties on SPItemEventReceiver  describes very well when above 3 returns null and when they return values. The summary is as following
Here are the results for a list:
List
BeforeProperties
AfterProperties
properties.ListItem
ItemAdding
No value
New value
Null
ItemAdded
No value
New value
New value
ItemUpdating
No value
Changed value
Original value
ItemUpdated
No value
Changed value
Changed value
ItemDeleting
No value
No value
Original value
ItemDeleted
No value
No value
Null
Here is the same test against a document library:
Library
BeforeProperties
AfterProperties
properties.ListItem
ItemAdding
No value
No value
Null
Now, the event handler method provides the SPItemEventProperties properties object which provides three ways to access the field values:
-          properties.ListItem[FieldName]
-          properties.AfterProperties
-          properties.BeforeProperties
The link Working with BeforeProperties and AfterProperties on SPItemEventReceiver  describes very well when above 3 returns null and when they return values. The summary is as following
Here are the results for a list:
List
BeforeProperties
AfterProperties
properties.ListItem
ItemAdding
No value
New value
Null
ItemAdded
No value
New value
New value
ItemUpdating
No value
Changed value
Original value
ItemUpdated
No value
Changed value
Changed value
ItemDeleting
No value
No value
Original value
ItemDeleted
No value
No value
Null
Here is the same test against a document library:
Library
BeforeProperties
AfterProperties
properties.ListItem
ItemAdding
No value
No value
Null
ItemAdded
No value
No value
New value
ItemUpdating
Original value
Changed value
Original value
ItemUpdated
Original value
Changed value
Changed value
ItemDeleting
No value
No value
Original value
ItemDeleted
No value
No value
Null
 
But while accessing the BeforeProperties and AfterProperties, you cant access them directly as shown in the following code
 
if (properties.ListItem["FieldName"] != properties.AfterProperties["FieldName"])
{
    properties.Cancel = true;
    properties.ErrorMessage = "This column cannot be changed";
}
The above code works fine when the internal name of the column is same as display name. If the field display name has space, for example:  If FieldName =  ‘Reason For Change’ then the internal name will be ‘Reason_x0020_For_x0020_Change’ and in suchcase the above code will fail.
So It’s always better to use the Internal FieldName by default  while working with AfterProperties and BeforeProperties. You can use any of following was to access the value
properties.AfterProperties["Reason_x0020_For_x0020_Change"].ToString();
or
foreach (DictionaryEntry entry in properties.AfterProperties)
               {
                   if (entry.Key.Equals(["Reason_x0020_For_x0020_Change"))
                       editedReasonForChange = entry.Value.ToString();
               }
 
So my code for comparison looks like as following:
 
 
/// <summary>
       /// An item is being updated.
       /// </summary>
     public override void ItemUpdating(SPItemEventProperties properties)
     {
       base.ItemUpdating(properties);
       string originalReasonForChange = string.Empty;
       string originalImpact = string.Empty;
       string editedReasonForChange = string.Empty;
       string editedImpact = string.Empty;
       originalReasonForChange = properties.ListItem[(["Reason_ For _Change"].ToString();
       originalImpact = properties.ListItem["Impact"].ToString();
       editedReasonForChange =    properties.AfterProperties[(["Reason_x0020_For_x0020_Change"].ToString();
       editedImpact = properties.AfterProperties[["Impact"].ToString();
//Execute the code only following 2 fields value is changed
       if (editedImpact.ToLower() != originalImpact.ToLower() ||                                 editedReasonForChange.ToLower() != originalReasonForChange.ToLower())
 
       SaveUpdatesToDB(editedImpact, editedReasonForChange, properties.ListItem[SnapItConstants.ChangeReportListFields.TASK_GUID].ToString(), properties.ListTitle);
           }
       }
 
 
 
Happy Coding!!
 
 
 

No comments:

Post a Comment