Understanding event receivers in a SharePoint survey

SharePoint provides great support for creating surveys in your sites.  Under the covers this is just a list, like everything else in SharePoint.  The difficult thing with a survey is the ability to determine when it is complete.  The survey feature gives you the ability to create multiple pages in your survey by putting page breaks between questions.  When we have a survey with multiple pages the event handlers fire in the following order...

After the first page is submitted the ItemAdding and ItemAdded events fire.

Subsequent paging clicks fire the ItemUpdating and ItemUpdated events.

Even after the survey is completed and the user returns to update the information the ItemUpdating and ItemUpdated events fire.

I built the following utility method to help figure some of this out.  With event handlers it is really helpful to determine what is available.  All it really does is take the list item XML, BeforeProperties, AfterProperties and write them out to a text file.  Typically the Before/AfterProperties give all the detail we need, but there are several fields or attributes that are hidden and made available in the XML.  One thing to note is that the BeforeProperties collection is only populated for document libraries, so we don't expect it to be populated for this exercise.

 private void WriteProperties( SPItemEventProperties properties, string fileName ) {
    Stream stream = new FileStream( @"c:\" + fileName, FileMode.Create, FileAccess.Write );
    StreamWriter writer = new StreamWriter( stream );
    writer.WriteLine( "******** Fields **********" );
    writer.WriteLine( "List ID: " + properties.ListId.ToString() );
    writer.WriteLine( "List Item ID: " + properties.ListItemId.ToString() );
    
    
    if( properties.ListItem != null ) {
        SPListItem item = properties.ListItem;
        writer.WriteLine( item.Xml );
    }
    
    writer.WriteLine( "******** Before Properties ********" );
    foreach ( DictionaryEntry entry in properties.BeforeProperties ) {
        writer.WriteLine( String.Format( "{0}: {1}", entry.Key, entry.Value ) );
    }

    writer.WriteLine();
    writer.WriteLine();

    writer.WriteLine( "******** After Properties ********" );
    foreach ( DictionaryEntry entry in properties.AfterProperties ) {
        writer.WriteLine( String.Format( "{0}: {1}", entry.Key, entry.Value ) );
    }
    writer.Flush();
    writer.Close();
    stream.Dispose();
}

 

To examine the survey events I wrote an ItemAdded and ItemUpdated event receiver and just made a call to the WriteProperties method to output the XML and AfterProperties collection.  I created a survey that has three questions each separated by a page break.  After completing the first question and clicking the 'Next' button the ItemAdding and ItemAdded events fire as noted previously.  From the ItemAdded event we see a hidden field in the Xml output called 'ows_owshiddenversion'.  The value of this property is '1'.  Another field in the Xml is 'ows_Completed' and it has a value of '255'.  Neither of the fields mean much to us right now, but becomes important in the next steps. 

 

In completing the second question (page) the ItemUpdating and ItemUpdated events are fired.  The 'ows_owshiddenversion' field is incremented to '2' in the item.Xml and is added to the AfterProperties collection, although the value there is still '1'.  The 'ows_Completed' field retains its previous value of '255'.  I added some code to the ItemUpdated event in order to track the value of the Completed field.  The updated ItemUpdated event is shown below.

 

 public override void ItemUpdated( SPItemEventProperties properties ) {
    WriteProperties( properties, "surveyitemupdated.txt" );

    if ( properties.ListItem["Completed"] != null ) {
        WriteProperties( properties, "surveycompleted"+ properties.ListItem["Completed"].ToString() +".txt" );
    }
}

The next step is to complete the third and last question.  The button for the form changes from a 'Next' button for the previous questions to a 'Finish' button.  Completing the question and clicking the 'Finish' button again calls the ItemUpdating and ItemUpdated event.  This time the AfterProperties collection shows the 'owshiddenversion' value to be '2' and the 'Completed' field changes from '255' to '1'.  The 'ows_owshiddenversion' field is continually incremented as we change the value of our survey and go from page to page.  Since the underlying survey item is updated between page requests it just provides a type of version number.  Given that a user can come back and edit a survey at any time, and SharePoint starts the user off with the first question in the survey when 'Edit' is selected it is difficult to determine anything from this value.

The one thing we can determine is when the survey is completed, although we can only tell when it is completed the first time.  After that the completed attribute or field retains the value of '1' throughout the lifetime of the list item.  So we know that it was completed at some time in the past, but not much else.