Reorder new Content Type fields on the fly

At some point in time you will inevitably need to add a new field to an existing content type programmatically.  For example, adding Lookup column to a Content Type.  You can’t do it within the Content Type CAML if the target list doesn’t exist. It’s common to add the lookup within a FeatureActivated event after the list is created.

This is accomplished quite easily using the Add method of the FieldLinks property on the Content Type itself.  The draw back is that the new field is always added to the end of the list, and from a presentation standpoint, this may not be desired.

For example, adding lookups to the content type like so:

 

       
private void CreateDigitalReleasesList(SPWeb web)
{
  SPList list = web.Lists.TryGetList(Constants.DigitalReleasesList_Name);
  if (list == null)
  {
    Guid listID = web.Lists.Add(Constants.DigitalReleasesList_UrlName,
      "Used to record Digital Distributor Releases", 
      SPListTemplateType.GenericList);
    list = web.Lists[listID];
    list.Title = Constants.DigitalReleasesList_Name;
    list.OnQuickLaunch = true;
    list.Update();

    SPList ddList = web.Lists.TryGetList(DistributorsList_Name);
    SPList relList = web.Lists.TryGetList(ReleasesList_Name);

    if (ddList != null && relList != null)
    {
       SPFieldLookup ddLookup =
         (SPFieldLookup) web.Fields[fieldName_DistributorLookup];
       SPFieldLookup relLookup = 
         (SPFieldLookup) web.Fields[fieldName_ReleaseLookup];

       AddFieldToContentType(web, 
         contentType_DigitalRelease, ddLookup);
       AddFieldToContentType(web, 
         contentType_DigitalRelease, relLookup);
    }


    AssociateContentType(web, Constants.DigitalReleasesList_Name, 
      Types.Constants.contentType_DigitalRelease);
  }
}

public static void AddFieldToContentType(SPWeb web, string contentType, SPField field)
{
  SPContentTypeId ctId = new SPContentTypeId(contentType);
  SPContentType ct = web.ContentTypes[ctId];
  ct.FieldLinks.Add(new SPFieldLink(field));
  ct.Update();
}

Results in the presentation of the fields at the bottom of the form like so:

Capture

 

The solution, is to use the Reorder method on the FieldLinks collection, however this requires you to layout the names of each field in the array in the order that you want.  If you were to construct this array using literals, that could easily result in unnecessary maintenance of the code when you need to make a change to the column names, etc. during development or updates.

It would be easier to just specify the order of the new field at the time that you link it and be completely generic and frankly agnostic of the field names as much as possible.  Therefore here’s a modified version of the sample code exposed above. Pay particular attention to the modification of AddFieldToContentType.

       
private void CreateDigitalReleasesList(SPWeb web)
{
  SPList list = web.Lists.TryGetList(Constants.DigitalReleasesList_Name);
  if (list == null)
  {
    Guid listID = web.Lists.Add(Constants.DigitalReleasesList_UrlName,
      "Used to record Digital Distributor Releases", 
      SPListTemplateType.GenericList);
    list = web.Lists[listID];
    list.Title = Constants.DigitalReleasesList_Name;
    list.OnQuickLaunch = true;
    list.Update();

    SPList ddList = web.Lists.TryGetList(DistributorsList_Name);
    SPList relList = web.Lists.TryGetList(ReleasesList_Name);

    if (ddList != null && relList != null)
    {
       SPFieldLookup ddLookup =
         (SPFieldLookup) web.Fields[fieldName_DistributorLookup];
       SPFieldLookup relLookup = 
         (SPFieldLookup) web.Fields[fieldName_ReleaseLookup];

       AddFieldToContentType(web, 
         contentType_DigitalRelease, ddLookup, 2);
       AddFieldToContentType(web, 
         contentType_DigitalRelease, relLookup, 3);
    }


    AssociateContentType(web, Constants.DigitalReleasesList_Name, 
      Types.Constants.contentType_DigitalRelease);
  }
}

public static void AddFieldToContentType(SPWeb web, string contentType, SPField field, int order)
{
  SPContentTypeId ctId = new SPContentTypeId(contentType);
  SPContentType ct = web.ContentTypes[ctId];

  // Generate a string array with the existing order of the fields.
  List fieldOrder = new List();
  for (int i = 0; i < ct.FieldLinks.Count; i++)
  {
    fieldOrder.Add(ct.FieldLinks[i].Name);
  }

  // Add the new field.
  ct.FieldLinks.Add(new SPFieldLink(field));
  ct.Update();

  // Now insert the new field in the proper order.
  // You might think you want to decrement the value of order,
  // since the generic list array is zero based, but the first 
  // item in the array is the actual "ContentType" field
  // so no decrement is necessary.
  fieldOrder.Insert(order, field.InternalName);
  ct.FieldLinks.Reorder(fieldOrder.ToArray());
  ct.Update();
}

The end result is similar to the following:

Capture

Hope you find this helpful!

– Keith

4 Replies to “Reorder new Content Type fields on the fly”

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s