This post is migrated from previous hosting provider. There are still some issues with old posts. Please make a comment on this post with any issues.

Web Part Properties - part 6 - Complex Properties

Tags: .NET, SharePoint, Web Parts

To end my series of Web Part properties I would like to show how to store more complex values than just strings or integers. What happens if you would like to store a more complex object; an array or a coordinate etc?

Editing these properties with the standard generated interface using the WebBrowsable and Personalizable attributes will not work, since it only accepts basic types, shown in part 1. To make these properties editable you have to (almost…continue reading) create an EditorPart, shown in part 2, and control the properties in the SyncChanges and ApplyChanges methods.

Note: For more information on which basic types that can be used in the standard toolbar see the PropertyGridEditorPart documentation on MSDN.

SharePoint Designer and complex properties

If you are using SharePoint Designer to edit your Web Parts, you can manage your complex properties a little bit more. For example if you store have string array, it will not be visible in the web interface, but it can be edited in SharePoint Designer.

  1: [WebBrowsable]
  2: [Personalizable]
  3: public string[] AnArray {
  4:     get;
  5:     set;
  6: }

The property above will not be seen in the web interface but in SharePoint Designer it will look like this:

SPD

If you click on the ellipsis button you will get a dialog in which you can edit the string array.

Custom objects without EditorParts

But if you still don’t want to create your own EditorPart you can use some .NET development techniques, familiar to you who have been working a lot with WinForms.

Let’s say that we want to have a Coordinate property that we would like to use in our web part, the class should look like this:

  1: public class Coordinate {
  2:     public float Latiude;
  3:     public float Longitude;
  4:     public override string ToString() {
  5:         return this.Latiude.ToString(CultureInfo.CurrentCulture) + 
  6:                ":" + 
  7:                this.Longitude.ToString(CultureInfo.CurrentCulture);
  8:     }
  9: }

And we expose it through our web part like this:

  1:  [WebBrowsable]
  2:  [Personalizable]
  3:  public Coordinate Coordinate {
  4:     get;
  5:     set;
  6: }

This property will not be shown in the web interface and will not be editable in SharePoint Designer. Now to get this to work, editable in the web interface as well as in SPD, we have to create an implementation of the ExpandableObjectConverter class. We will override four methods so we can convert a Coordinate to and from a string representation. The string representation is implemented in the ToString() in the code above. The whole implementation of the class looks like this:

  1: public class CoordinateConverter : ExpandableObjectConverter {
  2:     public override bool CanConvertTo(ITypeDescriptorContext context, 
  3:                          System.Type destinationType) {
  4:         if (destinationType == typeof(Coordinate))
  5:             return true;
  6:         return base.CanConvertTo(context, destinationType);
  7:     }
  8:     public override object ConvertTo(ITypeDescriptorContext context, 
  9:                            CultureInfo culture, object value, 
 10:                            System.Type destinationType) {
 11:         if (destinationType == typeof(System.String) && 
 12:             value is Coordinate) {
 13:             Coordinate coord = (Coordinate)value;
 14:             return coord.ToString();
 15:         }
 16:         return base.ConvertTo(context, culture, value, destinationType);
 17:     }
 18: 
 19:     public override bool CanConvertFrom(ITypeDescriptorContext context, 
 20:                          System.Type sourceType) {
 21:         if (sourceType == typeof(string))
 22:             return true;
 23:         return base.CanConvertFrom(context, sourceType);
 24:     }
 25:     public override object ConvertFrom(ITypeDescriptorContext context, 
 26:                            CultureInfo culture, object value) {
 27:         if (value is string) {
 28:             try {
 29:                 string s = (string)value;
 30:                 string[] arr = s.Split(':');
 31:                 Coordinate coord = new Coordinate();
 32:                 coord.Latiude = float.Parse(arr[0], 
 33:                                 CultureInfo.CurrentCulture);
 34:                 coord.Longitude = float.Parse(arr[1], 
 35:                                   CultureInfo.CurrentCulture);
 36:                 return coord;
 37:             }
 38:             catch {
 39:                 throw new ArgumentException("Can not convert '" + 
 40:                           (string)value + "' to type a Coordinate");
 41:             }
 42:         }
 43:         return base.ConvertFrom(context, culture, value);
 44:     }
 45: }

To make SharePoint and SharePoint Designer aware of that we now can convert our Coordinate class to a string representation we have to set the TypeConverter attribute on our Coordinate class. The final Coordinate class should look like this:

  1: [TypeConverter(typeof(CoordinateConverter))]
  2: public class Coordinate {
  3:     public float Latiude;
  4:     public float Longitude;
  5:     public override string ToString() {
  6:         return this.Latiude.ToString(CultureInfo.CurrentCulture) + 
  7:                ":" + 
  8:                this.Longitude.ToString(CultureInfo.CurrentCulture);
  9:     }
 10: }

If we now modify our web part we will see this in the web interface, sweet huh?

Coordinate

If we try to set it to any other value than we allow in our ConvertFrom method above, then we will get a nice error:

Coordinate error

The Coordinate property can also be edited in SharePoint Designer:

Coordinate editing in SPD

Other methods

There are other ways to make your web part handle complex properties. Wesley Bakker has a nice write up on how to use JSON notation to store and edit the values.

That was all folks…

5 Comments

  • Wictor said

    Hi, I did override the ToString() method to get the coordinate to show up nice in the UI like this: Lat:Lon when the ToString() method is used. I think it is a good practice to do this for custom types that have visual representation, also I use this method in the ExpandableObjectConverter to generate the string.

  • Ian said

    Wictor, I'm trying to do something similar with a much more complex class hierarchy. I'm wondering if it's actually possible.

    Have you considered trying to do the same thing through the use of class attributes such as the PersistenceMode? I can succesfully generate some quite complicated content in the SharePoint Designer html view, although I find most of the sub-elements are read only - I'm wondering if I could discuss this with you to get some thoughts or take a look at http://sharepoint.stackexchange.com/questions/46912/sharepoint-designer-not-saving-changes

Comments have been disabled for this content.

About Wictor...

Wictor Wilén is the Nordic Digital Workplace Lead working at Avanade. Wictor has achieved the Microsoft Certified Architect (MCA) - SharePoint 2010, Microsoft Certified Solutions Master (MCSM) - SharePoint  and Microsoft Certified Master (MCM) - SharePoint 2010 certifications. He has also been awarded Microsoft Most Valuable Professional (MVP) for seven consecutive years.

And a word from our sponsors...