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.
|
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!!