Friday, March 9, 2012

Detection of field value changes in document library

There is pretty easy way to detect change of field value in document library. You can use EventReceiver attached to your content type. ItemUpdating is a good place detects changes and performs validation if required. In my case it was required to detect that value of field has changed and additionally to synchronize value of two fields and perform some additional validation of entered values.

First thing was to create content type based on document library

<ContentType ID="0x010100E9F562320B4441718C2F91D48268EFAD"               
         Name="CustomContentType"               
  Group="Custom Content Types"               
  Description="My Content Type with hidden fields"               
  Inherits="False"               
  V2ListTemplateName="doclib"               
  Version="0">    
     <FieldRefs> 
     ...
     <FieldRef ID="{C5E94AC7-EE52-4409-B219-6D6E9B33A172}" 
         Name="MyCustomField" Required="FALSE"/>     
     <FieldRef ID="{B35E5E3C-A0DE-4579-A6C7-D0C83C993A6B}" Name="MyCustomFieldHidden"
         Required="TRUE" ShowInDisplayForm="FALSE" 
         ShowInEditForm ="TRUE" ShowInListSettings="FALSE" ShowInNewForm="TRUE"/> 
     </FieldRefs>
</ContentType>


In next step, I have created event receiver and override ItemUpdating method.

public class CustomFieldEventHandler : SPItemEventReceiver
{
   public override void ItemUpdating(SPItemEventProperties properties)
   {
      base.ItemUpdating(properties);

      IFieldValidator customFieldValidator = new CustomFieldValidator();

      if (propertyHasChanged(properties, "MyCustomField"))
      {
         checkAndSyncFields(properties,
                            accessGroupFieldValidator, 
                            "MyCustomField", 
                            "MyCustomFieldHidden");
      }
      else if (propertyHasChanged(properties, "MyCustomFieldHidden"))
      {
         checkAndSyncFields(properties, 
                            accessGroupFieldValidator, 
                            "MyCustomFieldHidden", 
                            "MyCustomField");
      }        
}


In ItemUpdating I'm checking if field value has changed, if so, I'm validating it against my rules and updating other field to make sure both have the same value.

Code for checking if field has changed is pretty simple

private bool propertyHasChanged(SPItemEventProperties properties, string fieldName)
{
   string beforeProp = properties.BeforeProperties[fieldName] as string;
   string afterProp = properties.AfterProperties[fieldName] as string;

   return string.Compare(beforeProp, afterProp) != 0;
}


Validation and synchronization is also fairly simple task in this case.

private void checkAndSyncFields(SPItemEventProperties properties, 
                                IFieldValidator fieldValidator, 
                                string sourceFieldName, 
                                string destFieldName)
{
   string fieldValue = properties.AfterProperties[sourceFieldName] as string;

   if (!fieldValidator.Validate(fieldValue))
   {
      properties.Status = SPEventReceiverStatus.CancelWithError;
      properties.ErrorMessage = fieldValidator.GetValidationMessage(sourceFieldName, 
                                                                    fieldValue);
      properties.Cancel = true;
   }
   else
   {
      properties.AfterProperties.ChangedProperties[destFieldName] = 
                      properties.AfterProperties[sourceFieldName];
   }
}


Validation on EventReceiver level is very nice, since it is working also when list is accessed externally using web services. This way we can assure that only allowed values can be entered into our list.

Last thing to do is to register our Event receiver in our content type

<XmlDocument NamespaceURI="http://schemas.microsoft.com/sharepoint/events">
    <spe:Receivers xmlns:spe="http://schemas.microsoft.com/sharepoint/events">          
        <spe:Receiver>
            <spe:Name>CustomFieldEventHandler</spe:Name>
            <spe:Type>ItemUpdating</spe:Type>
            <spe:Assembly>$SharePoint.Project.AssemblyFullName$</spe:Assembly>
            <spe:Class>CustomFieldSync.CustomFieldEventHandler</spe:Class>
        </spe:Receiver>
     </spe:Receivers>
</XmlDocument>

And we are done

Have fun!

No comments:

Post a Comment