Second Life of a Hungarian SharePoint Geek

January 9, 2010

Creating real multi column fields for SharePoint

Filed under: Custom fields, SharePoint — Tags: , — Peter Holpar @ 01:35

SharePoint contains out of the box support for multi column fields. The base of these fields is the SPFieldMultiColumn class. The ParentType of the field definition should be MultiColumn  for these columns.

A typical sample for multi column field type is the US Address Field with MapPoint Picker Dialog. If you have ever created or worked with such field types you know it has several drawbacks that derive mainly from the simple fact, that despite of the field type name, values of the “multi” columns are stored in a single column, separated by “;#” characters.

Let’s see some of these drawbacks:

  1. You cannot handle the individual columns of the field separately on the list views, for example, include only the US address state column in the view, but no street address.
  2. The same is true for ordering or filtering the items on the list views. You cannot create a filter on US address state column or order by the street address.
  3. It’s not possible to create CAML query filters for the individual columns of the field.
  4. You cannot create managed property for search on the individual columns of the field.

What are the alternatives for this situation? Why don’t we create a real multi column field? What are the requirements for this kind of field?

  1. That kind of custom field should have a master field, and slave fields.
  2. Only the master field should be available when you add the field to the list or content type.
  3. When you add the master field, it should automatically create the slave fields.
  4. When you remove the master field, it should automatically remove slave fields.
  5. Only the master field should have its field control, that addresses (read and write) slave field values, display them in edit or display mode and does all the validation for the fields.
  6. The consequence of the previous statement is that only the master field should be visible on the new / edit / display forms, the slave fields must be invisible.
  7. If you don’t want the master field to provide the user interface for the slave fields, then you should not hide the slave fields as described above. This situation can be useful sometimes and requires a little different handling of fields as described here. We don’t discuss this situation in the current post.

In this post I will show you code for real multi column fields only for lists, but you can apply the same technique for content types either.

The following codes should be included in the code of the master field class. You can use built-in field types as slave fields. In the current example I will use only a single text slave field. You can extend that based on the sample.

When the master field is added, we add all of our slave fields either.

  1. public override void OnAdded(SPAddFieldOptions op)
  2. {
  3.     AddField("yourSlaveField");
  4.     base.OnAdded(op);
  5. }

We get the fields of the list, set some important properties and add the slave field as a new text field to the field collection. Of course, you are free to create other field types, like dates, numbers or yes/no values if you wish.

We should set the value of the ReadOnlyField property to true. Using this setting the slave field will be hidden on the edit and new form. You can achieve the same by setting the ShowInEditForm and ShowInNewForm properties of the slave fields to false.

To hide the slave field on the display form we set the value of the ShowInDisplayForm property of the field to false.

We set the value of the ShowInListSettings property to false. This setting hides the slave field on the List Settings page, so users can not manipulate that directly from the user interface.

Finally, we set the value of the RelatedField property of the slave field to the value of the Title property of the master field. We will use this later to get the slave fields related to the master field when removing the master field from the list.

  1. private SPField AddField(string fieldName)
  2. {
  3.     SPList list = SPContext.Current.List;
  4.     SPFieldCollection fields = list.Fields;
  5.     SPField field = null;
  6.  
  7.     if (!String.IsNullOrEmpty(fieldName))
  8.     {
  9.         field = new SPFieldText(fields, SPFieldType.Text.ToString(), fieldName);
  10.         field.ReadOnlyField = true;
  11.         field.ShowInDisplayForm = false;
  12.         field.ShowInListSettings = false;
  13.         field.RelatedField = Title;
  14.         fields.Add(field);
  15.         list.Update();
  16.     }
  17.     return field;
  18. }

On the master field removal we also remove all of the slave fields.

  1. public override void OnDeleting()
  2. {
  3.     RemoveRelatedFields();
  4.     base.OnDeleting();
  5. }

We identify these fields using the RelatedField property. If the value of this property equals to the Title property of the master field, the field is considered a slave field of the current field.

There are two tricks in this method. First, we should iterate the list fields using a for loop, iterating from the last item to the first one to avoid the catches of modifying the collection being iterated on. Second, we have to set the ReadOnlyField property of the slave field to false and call the Update method to propagate changes. Without that we would get an exception when trying the field deletion.

  1. private void RemoveRelatedFields()
  2. {
  3.     SPFieldCollection fields = SPContext.Current.List.Fields;
  4.     for (int i = fields.Count – 1; i > -1; i–)
  5.     {
  6.         SPField field = fields[i];
  7.         if (field.RelatedField == Title)
  8.         {
  9.             field.ReadOnlyField = false;
  10.             field.Update();
  11.             fields.Delete(field.InternalName);
  12.         }
  13.     }
  14. }

When rendering the master field control, you should read the values of the slave fields, and when the field is in edit or new mode and being saved, you should catch the save event and store the values from the field control to the slave fields.

In this post I won’t detail how you can access other field values from your field control. You can read about that in my former posts:

  • Interacting with other fields from a custom field
  • Interacting with other fields from a custom field, 2nd part
  • Cross field, cross item, cross list or even more complicated validations on SharePoint forms
  • Here you find the info required to create your own save method in the master field:

    After adding the master field to the list, the slave field won’t be visible on the List Settings page, the display, new and edit forms, but it will be visible on the Edit View page, so you can add master and slave fields independently, and can use them to sort and filter the items in the views.

    5 Comments »

    1. Thanks for this fantastic overview of multi column fields in SharePoint. We’d love if you linked your tutorials on http://www.facebook.com/office

      Keep up the great posts!

      Cheers,
      Andy
      MSFT Office Outreach Team

      Comment by Andy — January 9, 2010 @ 01:50

    2. Some misprint. Instead of
      for (int i = fields.Count – 1; i > -1; i–)
      should be
      for (int i = fields.Count – 1; i > -1; i–-)

      Comment by Misha Ulyutin — January 30, 2010 @ 13:30

      • Hi Misha,

        You are absolutely right, it should be i--, thanks for alerting me! It seems to be an issue with the code snippet add-in of my blogging application, as the i-- is there in the original code, and when I open the post from the web, it is shown as i-- in the editor and in the preview mode also. Pretty strange. I should figure out how to workaround that.

        It is funny as when I was to reply you in this comment that it should be i--, it was displayed on the web as it should be i-, so maybe the blog engine is that removes the extra – signs. I had to put the expression in a code block.

        Peter

        Comment by pholpar — January 30, 2010 @ 15:28

    3. And, I think, better use InternalName of the master field for property RelatedField of the slave field, because Title can be changed, or we should handle this action

      Comment by Misha Ulyutin — February 1, 2010 @ 16:38

    4. Yeah, Misha is right, that’s a problem we had.

      Comment by Andy Burns — August 17, 2010 @ 11:22


    RSS feed for comments on this post. TrackBack URI

    Leave a comment

    Create a free website or blog at WordPress.com.