Walkthrough 2 – Developing an Event Receiver for a Document Library
You can also develop event receivers that run on document libraries. The basic techniques are the same as for custom lists. In more advanced scenarios you can hook up an event receiver when files are checked in and checked out, attachments added, updated or deleted, files moved or converted.
In this walkthrough I will explain how you can write a simple event receiver for a document library. This event receiver will calculate a code for each Word 2007 document that is added or uploaded based on the selected planet and the number of documents already uploaded to the document library.
Preparation
- Create a document library with the name Planet Documents, based on a Word 2007 document template.
- Add a column with the name Code. This column will contain a calculated code and is of type Single line of text . Set the maximum number of characters to 20.
- Add a column with the name Planet. This column is a lookup column that points to the Planets list.
Step 1 – Create the event receiver
1. Open Visual Studio 2008 and create a class library project with the name DocumentsEventReceiver.
2. Add a reference to the Microsoft.SharePoint.dll which can be found on the .NET tab under the label Windows SharePoint Services.
3. Add the following using statement to the top of the class file:
using Microsoft.SharePoint;
4. Give your class the name DocumentItemEventReceiver and let it inherit from SPItemEventReceiver.
public class DocumentItemEventReceiver: SPItemEventReceiver
{
// add your code here
}
5. You want to calculate the code for a document. This can only be achieved if the item is already available in the ListItem property of the properties argument. Therefore you have to add an event handler for the ItemAdded event. Add therefore the following code:
public override void ItemAdded(SPItemEventProperties properties)
{
base.ItemAdded(properties);
}
4. Here follows the complete code. You can find some explanation below the code fragment.
public override void ItemAdded(SPItemEventProperties properties)
{
// when a Word document is created from within the document library or uploaded to the document library,
// the ItemAdded event can be triggered get the name of the planet that needs to be saved.
int planetid = 0;
int.TryParse(properties.AfterProperties["Planet"].ToString(), out planetid);
// use the using syntax to avoid memory leaks caused by the SPWeb object
using (SPWeb web = properties.OpenWeb())
{
try
{
// get the Planet list (will be queried for existing planet name)
SPList planetList = web.Lists["Planets"];
SPListItem planetItem = planetList.GetItemById(planetid);
// then query the current document library for documents for this planet
SPList list = web.Lists[properties.ListId];
// build the query: by setting the sort order to descending, which retrieve the document with the highest code first
// (I'm aware that this is not completely correct as the alfabetical MARS-10 will be considered ordered behind MARS-9,
// but it is for demo purposes only).
SPQuery query = new SPQuery();
query.Query = string.Format(
"<Where><BeginsWith><FieldRef Name=\"Code\" /><Value Type=\"Text\">{0}</Value></BeginsWith></Where>"
+ "<OrderBy><FieldRef Name=\"Code\" Ascending=\"FALSE\" /></OrderBy>", planetItem["Planet"]);
// if you store the documents in folders, you will also have to set the ViewAttributes property of the query
query.ViewAttributes = "Scope = 'Recursive'";
// execute the query
string code = null;
SPListItemCollection items = list.GetItems(query);
if (items != null && items.Count > 0)
{
SPListItem item = items[0];
string oldcode = item["Code"].ToString();
// Retrieve the number after the - sign
int counter = 1;
if (oldcode.Contains("-"))
int.TryParse(oldcode.Substring(oldcode.IndexOf("-") + 1), out counter);
// calculate the new code
code = planetItem["Planet"].ToString().ToUpper() + "-" + (counter + 1).ToString();
}
else
{
// this is the first document for this planet
code = planetItem["Planet"].ToString().ToUpper() + "-1";
}
//Stop other events from firing while this method executes
this.DisableEventFiring();
// save the new value
properties.ListItem["Code"] = code;
properties.ListItem.SystemUpdate();
}
catch (Exception ex)
{
properties.ErrorMessage = string.Format("An error occurred during execution of ItemAdding event: {0}.", ex.Message);
properties.Status = SPEventReceiverStatus.CancelWithError;
properties.Cancel = true;
}
finally
{
//Enable event firing again
this.EnableEventFiring();
}
}
}
The code start by encapsulating the whole in a using (SPWeb web = properties.OpenWeb()) this to dispose from the SPWeb instance and avoid memory leaks when the code finishes running. The rest of the code is wrapped in a try-catch-finally block in order to handle an eventual error correctly: generate an error message, set the status to CancelWithError and cancel the event handler.
Before the list item is updated, you have to disable the event receiver from firing by executing the this.DisableEventFiring() method. In this case it is not really necessary because there is no ItemUpdating or ItemUpdated event handler. But if these event receivers are available executing the this.DisableEventFiring() method will avoid the ItemUpdating and/or ItemUpdated event handler from being executed.
Use the SystemUpdate() method of the list item to not modify the system columns like Created and Created By. This event receiver will work when a Word 2007 document is created from within the document library and when a Word 2007 document is uploaded. After the item is updated with the calculated code you have to execute the this.EnableEventFiring() method to enable the event receivers again. It’s a good practice to place these two methods as close to the Update method as you can.
Step 2 – Create the feature
The best way to deploy an event handler is by creating a feature that can be installed and activated to be used and can be deactivated and uninstalled if not needed anymore. As in the first walkthrough, the assembly containing the event handlers must be deployed to the Global Assembly Cache. The structure of the feature is exactly the same, except from the elements.xml file.
- The Receivers element must have the ListTemplateId set to 101 to add the event receiver to a document library
- The type of the event handler is ItemAdded
<Elements Id="{F5610B81-A2E2-4957-ABF2-B8ECCD765AF3}"
xmlns="http://schemas.microsoft.com/sharepoint/">
<Receivers ListTemplateId="101">
<Receiver>
<Name>PlanetDocumentAdded</Name>
<Type>ItemAdded</Type>
<SequenceNumber>1</SequenceNumber>
<Assembly>Walkthrough.DocumentsEventReceiver, Version=1.0.0.0, Culture=neutral, PublicKeyToken=841f382b41c47c60</Assembly>
<Class>Walkthrough.EventHandlers.DocumentItemEventReceiver</Class>
</Receiver>
</Receivers>
</Elements>
Each time a document is created or uploaded, the event handler will execute:

The event receiver will run for each document library in the site collection on which the features is deployed. If you want this event handler to only run on this particular document library, you could test on the list name in your code. A better way is to work with a content type that you can add to this document library, and add the event receiver to this content type.

Hi Karine,
Thanks for the post.
Can you please tell me.
If I have a list on a site and created the event receiver for it let’s say (itemAdded). Now, will that event reciver still work if I save the site as a template.
I mean, will it still work on the new instance of the site and list or not?
I would appreciate your feedback.
Hi Prakash,
The event receiver will still be attached to the list after creation of a new site instance based on the site template you saved. If you do it on the same server, then the DLL is still in the GAC and your event handler will work. But if you use the site template on a different server it will only work after you have deployed the DLL to the GAC.
Karine
Many Thanks for your feedback and it has saved my day. I am currently, writing my code on the test server but when I move it to production server then I will deploy it again so that it works there as well (like you pointed out).
I very much appreciate it.
You are the best..!