Karine Bosch’s Blog

On SharePoint

Walkthrough 3 – Developing an Event Receiver for a Content Type


If you want that a certain event receiver only fires on certain lists or document libraries, you can develop a content type and bind an event receiver to this content type.

In this walkthrough I will explain how you can write a simple event receiver for a content type. This walkthrough builds on the first one. The content type will be applied to the Planets list and will contain fields for:

  • the name of the planet
  • the number of moons
  • distance from the sun
  • orbital period (number of days the planet needs to turn around the sun)
  • minimum temperature
  • maximum temperature

Step 1 – Create the site columns

Content types are based on site columns, so you first have to define the necessary site columns. You can do this in CAML. Best practice is to create a separate XML file for each different step. Create a sitecolumns.xml file and add the following CAML. Each sitem column is defined in a <Field> element and has an own unique ID. You can specify information like internal name, display name, type of the column and description. You can use the Group attribute to specify the group of site columns to which the new columns will belong:

<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <!--Site Columns-->
  <Field
    ID="{C2A8588A-F8A2-4324-BE39-4962E2E75895}"
    Name="NumberOfMoons"
    DisplayName="Number of Moons"
    Description="The number of moons that turn around the planet."
    Type="Number"
    Group="Universe Site Columns"
    />
  <Field
    ID="{85F781F8-0AB3-433e-B828-DC0DD39AE695}"
    Name="Distance"
    DisplayName="Distance (in km)"
    Description="The distance from the sun."
    Type="Number"
    Group="Universe Site Columns"
    />
  <Field
    ID="{0E273391-2749-4c17-BCFD-009E2DC98F2F}"
    Name="OrbitalPeriod"
    DisplayName="Orbital Period (in earth days)"
    Description="The time necessary to turn around the sun calculated in earth days."
    Type="Number"
    Group="Universe Site Columns"
    />
  <Field
    ID="{7A86784F-65B3-4b48-8EAF-C77FFED7BB61}"
    Name="MinimumTemperature"
    DisplayName="Minimum temperature (in °C)"
    Description="Minimum temperature in °C at the surface of the planet."
    Type="Number"
    Group="Universe Site Columns"
    />
  <Field
    ID="{9677F5F2-4CA6-4d88-9DE1-3518DE4E2A01}"
    Name="MaximumTemperature"
    DisplayName="Maximum temperature (in °C)"
    Description="Maximum temperature in °C at the surface of the planet."
    Type="Number"
    Group="Universe Site Columns"
    />
</Elements>

Step 2 – Create the content type

Content types can also be created using CAML. The site columns that make up the content type are specified in separate <FieldRef> elements within a <FieldRefs> element. The definition of this content type looks as follows:

<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <!--Content Types-->
  <ContentType
    ID="0x0100A3897215697C447eB6612DF4CF4390FE"
    Group="Universe Content Types"
    Name="Planet">
    <FieldRefs>
      <FieldRef ID="{fa564e0f-0c70-4ab9-b863-0177e6ddd247}" DisplayName="Name" />
      <FieldRef ID="{C2A8588A-F8A2-4324-BE39-4962E2E75895}" />
      <FieldRef ID="{85F781F8-0AB3-433e-B828-DC0DD39AE695}" />
      <FieldRef ID="{0E273391-2749-4c17-BCFD-009E2DC98F2F}" />
      <FieldRef ID="{7A86784F-65B3-4b48-8EAF-C77FFED7BB61}" />
      <FieldRef ID="{9677F5F2-4CA6-4d88-9DE1-3518DE4E2A01}" />
    </FieldRefs>
  </ContentType>
</Elements>

Notice that the content type inherits from the Item content type, which has content type ID 0x01. A new content type ID of an inheriting content type is calculated as follows:

parent content type ID + 00 + GUID without minus signes and accolades.

The first <FieldRef> element is based on the Title column. This column has the Guid {fa564e0f-0c70-4ab9-b863-0177e6ddd247}. When deployed, the list items will behave as normal list items and have a Edit Control Block assigned to the Title column.

Planet all items

PS. Notice that the header of the view shows Title but when creating, editing or viewing list items, you will notice that the first field is labeled as Name.

Step 3 – Add the event receiver to the content type

We will use the event receiver created in the first walkthrough which checks if the newly entered planet already exists in the list or not. To bind an event handler to a content type, you have to add a <XmlDocuments> element into the <ContentType> element. This <XmlDocuments> element can contain 1 or more <XmlDocument> elements. The <Receivers> element is added as a child element to the <Document> element. Create a new XML file with f.e. the name contenttypes.xml and add the following CAML:

<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <!--Content Types-->
  <ContentType
    ID="0x0100A3897215697C447eB6612DF4CF4390FE"
    Group="Universe Content Types"
    Name="Planet">
    <FieldRefs>
      <FieldRef ID="{fa564e0f-0c70-4ab9-b863-0177e6ddd247}" DisplayName="Name" />
      <FieldRef ID="{C2A8588A-F8A2-4324-BE39-4962E2E75895}" />
      <FieldRef ID="{85F781F8-0AB3-433e-B828-DC0DD39AE695}" />
      <FieldRef ID="{0E273391-2749-4c17-BCFD-009E2DC98F2F}" />
      <FieldRef ID="{7A86784F-65B3-4b48-8EAF-C77FFED7BB61}" />
      <FieldRef ID="{9677F5F2-4CA6-4d88-9DE1-3518DE4E2A01}" />
    </FieldRefs>
    <XmlDocuments>
      <XmlDocument NamespaceURI="http://schemas.microsoft.com/sharepoint/events">
        <Receivers xmlns:spe="http://schemas.microsoft.com/sharepoint/events">
          <Receiver>
            <Name>PlanetEventHandler</Name>
            <Type>ItemAdded</Type>
            <SequenceNumber>10000</SequenceNumber>
            <Assembly>UniverseEventHandlers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=841f382b41c47c60</Assembly>
            <Class>UniverseEventHandlers.PlanetItemEventReceiver</Class>
            <Data></Data>
            <Filter></Filter>
          </Receiver>
        </Receivers>
      </XmlDocument>
    </XmlDocuments>
  </ContentType>
</Elements>

Step 4 – Create a list instance and bind the content type to the list instance

You can deploy the previous CAML to create the site columns and content types. In the user interface of the SharePoint site you can create a custom list and add the content type to it. BUT you can also create a list instance using the CAML element <ListInstance>. To bind a content type to a list instance you have to use the <ContentTypeBinding> element. Add a new XML file with f.e. the name listinstance.xml and add the following CAML to it:

<Elements Id="{F5610B81-A2E2-4957-ABF2-B8ECCD765AF3}"
          xmlns="http://schemas.microsoft.com/sharepoint/">
  <ListInstance
       FeatureId="00BFEA71-DE22-43B2-A848-C05709900100"
       Title="Planets"
       Description="List of planets based on Universe content type."
       Id="10002"
       TemplateType="100"
       OnQuickLaunch = "TRUE"
       Url="Lists/Planets">
  </ListInstance>
  <ContentTypeBinding ContentTypeId="0x0100A3897215697C447eB6612DF4CF4390FE" ListUrl="Lists/Planets"/>
</Elements>

You can read more about creating list instances in CAML here.

Step 5 – Create the feature.xml file

Your feature.xml will look as follows:

<Feature Id="{BA902EC0-2A2A-4ed3-BDC2-042D421F1B96}"
  Title="Event Handlers - Walkthrough 3"
  Description="This feature creates the content type for Event Handlers walkthrough 3."
  Scope="Site"
  Hidden="FALSE"
  ImageUrl="BPoint\BPoint.png"
  xmlns="http://schemas.microsoft.com/sharepoint/">
  <ElementManifests>
    <ElementManifest Location="sitecolumns.xml" />
    <ElementManifest Location="contenttypes.xml" />
    <ElementManifest Location="listinstance.xml" />
  </ElementManifests>
</Feature>

Step 6 – Deploy and test the feature

Deploy the feature and navigate to the Planets list. Click the New button to create a new item. Notice that you can choose between the standard Item and a Planet item. Choose Planet and add data for the planet Mars. Add a second item for the planet Venus. Try to add a second item for the planet Mars and you will see the error page displaying the message that the planet Mars already exists.

Notice also that the All Items view doesn’t display the fields of the content type. You have to add them manually to the standard view or create a new view.

Navigate to the List Settings page of the Planets list. Notice that the list has two content types: the default Item content type and the Planet content type.

Planet content type

You can manually remove the Item content type from the list.

If you want a customized view already attached to the list and only the custom content type available on the list, you will can define a custom list defintion in CAML that inherits from the list definition of the generic list. This topic will be explained in detail in a later post.

30 Comments »

  1. Hi, i have created contenttype with an item event receiver attached to my content type, this works ok, but when i try do delete whole list where this content type is attached, i get an error from my event receiver.. is this by design ?, and i cannot delete my list if ItemDeleting type of Event receiver is attached to my contenttype ?

    Comment by maciej samoraj | January 5, 2010 | Reply

  2. Can you tell me what your ItemDeleting event receiver exactly does? I’ll try to reproduce your problem during the weekend.
    Karine

    Comment by Karine Bosch | January 6, 2010 | Reply

  3. Hi!, thanks for your reply !
    My event receiver is just displing the message “Deleting items is disabled” i solved the problem, i just placed after base.ItemDeleting() (if this one is not executed properties.ListItem is always null) a condition
    if (properties.ListItem != null)
    {
    //set the error message and cancel status with an error
    }
    Now it works for me, so i do not need any help for now.

    Great article, Thanks!

    Comment by maciej samoraj | January 6, 2010 | Reply

  4. ….

    Hi, I’m a SP rookie, I’m doing an event by Content types for a task list I hope you can help me with my questions.

    If I have already created the task list, do I have to do the sitecolumns.xml?

    If the answer of the last question is yes, I would like to know if all the columns are necesary or what columns do I need to specify? because in the schema of my list I have “default” fields that I didn’t specify (with a Type=”Computed” like the one with Name=”LinkFilenameNoMenu”).

    Thanks for your help.

    Comment by c. | May 28, 2010 | Reply

  5. Hi,
    I think you best read also my post on custom content types and custom list definitions: https://karinebosch.wordpress.com/walkthroughs/creating-a-custom-list-definition-based-on-a-generic-list-using-a-custom-content-type/

    In your sitecolumns.xml you specify the extra fields you need. In your content type you inherit from event and add the extra fields. Follow my directions in the other post I mentioned to add these extra columns to your list.

    Comment by Karine Bosch | June 1, 2010 | Reply

  6. How do you make changes to the event handler after it’s been deployed?

    Comment by Brad | September 13, 2010 | Reply

  7. Brad,
    It denpends. If you only change the code of your event receiver, you can simply redeploy. If you also change the content type, then it depends on the changes: if you add a field to the content type, there is no problem to redeploy. But if you remove a field from the content type, you will have to add a feature receiver that removes the field also from the list.
    Karine

    Comment by Karine Bosch | September 14, 2010 | Reply

  8. Hi,

    This is a general question about attaching a event receiver on a content type.

    If I implement what you expose on this post then I create a new content type inheriting from the Planet content type.

    Would this new content type fire the events of it’s base Planet content type?

    Comment by Greg | February 12, 2011 | Reply

    • Greg,
      Yes, the event receivers are inherited by inherited content types.
      Stuart

      Comment by Stuart Fieldhouse | March 16, 2011 | Reply

  9. how can we know what event recievers are attached to the list ?

    Comment by amit | July 22, 2011 | Reply

  10. Hi amit, no out of the box SharePoint feature exists for this but there are various custom features developed that do this. You can find what you need on codeplex.
    Kind regards,
    Karine

    Comment by Karine Bosch | July 24, 2011 | Reply

  11. hi, i strictly follow your instruction to attach an event receiver to a content type but however i try the event receiver doesn’t work. i don’t understand why. i use SP 2010

    Comment by charles | August 25, 2011 | Reply

  12. Hi Charles. One thing to check for is whether you have the attribute Inherits=”TRUE” in your content type. The attribute must be set to FALSE, else the XmlDocuments part will be ignored.

    Great blog, Karine. This is one of the places I often find a solution.

    Comment by Thomas Jorgensen | September 7, 2011 | Reply

  13. Hello, thanks for the very useful post! It got me started on writing a custom event receiver for content type.

    But it seems that the event receiver is actually attached to the list inheriting the content type rather than content type itself. It might not make a difference for events, but for field operation events like , it will only trigger when a field is deleted from the list but not when it’s removed from the content type.

    Comment by Bill Yang (@zz_fish) | September 22, 2011 | Reply

  14. Bill,
    You’re right, an event receiver only executes on a list or library. The idea of defining a event receiver for a content type, is having it executed on each list or library that has this content type.

    Comment by Karine Bosch | September 22, 2011 | Reply

  15. I’ve got mixed up with public key token in step 3,
    please explain me, Where did you take it from?
    Thanks ahead!
    Nicki

    Comment by Nicki | October 2, 2011 | Reply

  16. You can download a tool named Reflector. Open your assembly using this tool, and you will see the public key token in the status bar at the bottom.

    Comment by Karine Bosch | October 3, 2011 | Reply

  17. Hi Karine!
    Thanks for the quick reply!

    I try to deploy the project but I get an error :”Cannot find this file specified in the manifest projectName\sitecolumns.xml” .
    The file is there.There is a Sharepoint project with 2 xml files :contenttypes.xml,sitecolumns.xml and a feature with feature.template.xml
    What can be the problem?

    Thanks ahead!!!
    Nickik

    Comment by Nicki | October 6, 2011 | Reply

  18. Hi Nick,
    I suppose there is something wrong with your manifest.xml. Are you developing on SharePoint 2007 or 2010? If 2007, are you building up your project structure manually or do you use a tool like wspbuilder? If 2010, are you using the Visual Studio Templates?
    Karine

    Comment by Karine Bosch | October 6, 2011 | Reply

  19. Hi Karine!
    Thanks again for your quick reply! I really appriciate it.

    I’m developing on Sharepoint 2010 and I’m tring to build a Content type project or an empty Sharepoint project like your instructions- with no success.
    I have a seperate event receiver project.
    How should I build it?

    Thanks ahead!
    Nicki

    Comment by Nicki | October 9, 2011 | Reply

  20. When you use the Visual Studio 2010 Templates for SharePoint 2010, it is a bit different then developing content types for SharePoint 2007. When you started of with an empty SharePoint project, you have to add a new item of type content type. You don’t have to create a different event receiver project, just add the event receiver in your project. But for the assembly name and class receiver, you have can work with the visual studio tokens.
    If you’re not sure about your code, you can send me your VS solution to karinebosch at hotmail dot com

    Comment by Karine Bosch | October 9, 2011 | Reply

  21. Karine, Thank you for this detailed post. I have a content type created on my site through SPD 2010. However, when I try to create a project (eventreceiver), i do not see the content name listed. I am a newbie.. what am I missing? Thanks in advance.

    Comment by Santosh Balan | November 30, 2012 | Reply

    • If you can see your content type in your site through the settings pages, you should see this content type in the list in Visual Studio. Are you also sure you used the correct URL to your SharePoint site when creating your project?

      Comment by Karine Bosch | December 1, 2012 | Reply

  22. Very helpful post.

    Comment by Amitt | June 21, 2013 | Reply

  23. Karen,
    When an item is added to the list, what account is being used for this. Is this created by user account (user who has created a new item) or system account.
    I am looking for a solution that the item is added by system account and not user account. In this way, the workflow can be started even anonymous user is adding a new list item. Currently workflow cannot be started by anonymous user.

    Comment by Aladdin | October 3, 2013 | Reply

  24. Thanks Karine for the quick reply. The blog you posted in above cannot solve my problem because looks like it is not easy or may be not possible to write power shell script to point to office 365-P1 plan. My problem is I like to trigger a workflow when an item is added by anonymous user. My environment is office 365-P1 plan.
    But you comment in above is promising. You are saying (and in theory it should be that way) in event receiver I can update an item and that is updated by system account. So even an item is added by anonymous user, if I update the item via event receiver, and if I write my workflow in update event, it should work.
    Did I understand this correctly?

    Comment by Aladdin | October 3, 2013 | Reply

    • Yes, you understood it correctly. I don’t think it’s the most proper solution but you can give it a try. You can also post your question at the forum and see if you get a helping answer.

      Comment by Karine Bosch | October 4, 2013 | Reply


Leave a comment