Adding a Tree Control column to SharePoint

Deployment
 
After running the stsadm addsolution command, I deployed this wsp to a specific web application using the following command.
 
stsadm -o deploysolution -name TreeListControl.wsp -urlhttp://mycheshireteamsver/sites/casfaq -allowgacdeployment -local
 
WSP Package Content
 
Root Files were copied into the filesystem and an iisreset ran.
 
Original Article …
 

Adding a Tree Control column to SharePoint
 One of the things that SharePoint is lacking out-of-the-box is a tree control field type.  In a recent project, we required one, so that list items and document library items could be tagged appropriately using hierarchical in-house taxonomies.
 
Additional requirements for this tree control included that multiple nodes in the tree were able to be selected, and that the data displayed in the tree could be maintained by non-IT Admin staff.
 
Luckily, SharePoint allows you to define and create your own custom field types.  We decided that a tree control that stored the tree node path for selected nodes as a string would suffice.  So, for example, the following:

 
would be stored as: “”Americas/North America/USA; Europe/United Kingdom””
 
To meet the requirement that it could be maintained by non-IT staff, it was decided to source the tree from a SharePoint list.  The list structure was defined to have the following columns:Title – unused, but always sensible to leave this field in your custom lists, as some SharePoint functionality expects it to be there.Level1Level2Levelx – The level columns hold the node names for that level of the tree control.  The root node of the tree is the name of the listHoverText – Tooltip text to be displayed when user hovers over that nodeShowCheckbox – if that node should display a checkbox or not
 
(click to see a version that isnt squashed down)
 
How to create the Custom Field
When creating a custom field, there are 3 aspects that must be addressed:

1) The Field Type Definition
2) The UI and logic for adding your field to a list
3) The UI and logic for your field when an item in that list is being edited
(Note: you could have a fourth section here if you wanted to customise the way your field was displayed when the list item properties were viewed, but I was happy for the tree node path to be displayed as text, so no customization was required).

The WSP package associated with this post installs the following files:
– …\TEMPLATE\CONTROLTEMPLATES\TreeListControl.ascx
– …\TEMPLATE\CONTROLTEMPLATES\TreeListEditControl.ascx
– …\TEMPLATE\XML\FLDTYPE_TreeList.XML
– TreeListControl.dll (to the GAC)
 

1 – The Field Type definition
There are two parts to defining your field – the code implements your field type, and the FLDTYPES_name.XML file that contains all the information SharePoint requires to implement your custom field.
1) The code that implements the field type
The class for your custom field is going to override one of the existing SPField types.  My class here, “TreeListControl.TreeListField” (contained in FieldDef.cs),  inherits from SPFieldsMultiLineText.  The major change to this class that mine is making is the addition of a “Dictionary” collection to hold the property values for the field:
 
//Dictionary of property values
privatestaticDictionary dictUpdatedPropertyValue =newDictionary();
//Properties in a delimited string
privatestring _delimitedPropertyValues;
 
When users choose to add this field (say as a custom column in a list) they are asked to set some properties about (the source list for the tree, number of levels, etc.).  These values need to be stored by your custom field so they can be used later on when implementing the field.  The dictionary collection is used to store these property values.  Until the values are put in the dictionary, they are held in a the _delimitedProperty values string.
 
I also added the following properties to allow me to access the dictionary:
 
///
/// Access the delimited properties for the control
///
publicstring DelimitedPropertyValues
{
    get {return dictUpdatedPropertyValue.ContainsKey(ContextId) ? dictUpdatedPropertyValue[ContextId] : _delimitedPropertyValues; }
   set {this._delimitedPropertyValues =value; }
}
 
 
And very importantly, I override the base field rendering control, so that my TreeList control will be rendered:
///
/// Override the field rendering control to use the custom TreeList control
///
publicoverride Microsoft.SharePoint.WebControls.BaseFieldControl FieldRenderingControl
{
   get
   {
      Microsoft.SharePoint.WebControls.BaseFieldControl TreeList =new TreeList();
      TreeList.FieldName = InternalName;
      return TreeList;
   }
}
 
 
The rest of the functions in this class are quite straight forward, and simply used for maintaining the values stored in the dictionary.

2) The FLD_type.XML
 
 This file defines the field for SharePoint, and gets deployed to …\12\TEMPLATE\XML. most of the fields in here are pretty self-explanatory, though I would like to highlight a few of them:

 
Note
Setting the parent type of the field to “Note” allows this field allows us to avoid the 255character limit that most of the other parent fields type’s have – a Note field has no character length restriction.
TreeListControl.TreeListField, TreeListControl, Version=1.0.0.0, Culture=neutral, PublicKeyToken=9f525b76b9e4fb66
This defines the assembly and class therein that implements this field.
 

   
       
   

As the comment indicates, the property schema section is where we define our field type has an additional hidden field used for holding our properties.  This “PropertySchema” was meant to allow you to define multiple property fields (one per property), but there is a bug that prevents this from working.  Hence, we store one property, which in actuality is a delimited string of all our properties.
 
 
 
 
 
 
 
2 – UI and Logic for adding your Field to a List
 
This basically refers to presenting a screen to allow a user to set or change the properties that your custom field uses, and storing these property settings.  So it deals with our “DelimitedPropertyValues” property above.
My Tree control is going to have 10 properties:

1. Site (string) – the name of the site holding the list of data that defines this tree.

2. ListName (string) – the name of this list holding the tree data.

3. Levels (int) – the number of levels this tree has.  user will select list via a dropdown.

4. SortByAlpha (bool) – whether the nodes in this list will be sorted alphabetically, or be displayed the way they occur in the list.

5. ShowSetNull (bool) – if a “Set this value to be null” link should be displayed beneath the tree.

6. ShowCheckboxes (bool) – if this tree should render checkboxes on nodes as defined in the list holding the tree data.

7. CheckBoxDisplay (string) – a string indicating if the checkboxes should be displayed on “All Nodes”, “Leaf nodes” or “List Defined” nodes.  User will select which one via a dropdown.

8. AutoCheckSubnodes (bool) – if a node containing subnodes is checked, should they all be automatically checked also.

9. ExpandCheckedNodes (bool) – if the tree should load in an expanded state, showing all nodes that have been checked.

10. ShowHoverText (bool) – indicates if the tree control should show the hover text as defined in the list holding the Tree data.

 
So, the first thing I need to do is to create a control that allows the user to set all of these properties when they use my custom field. 
 
In my fileset, the control is the TreeListEditField.ASCX file, and it gets deployed to …\12\TEMPLATE\CONTROLTEMPLATES.
 
The majority of this control is fairly straight forward, simple ASP.Net controls like Labels and TextBoxes to gather my property values, but you may not be familiar with the controls that enclose these, ie:

      
             
                   
 
 
The “InputFormSection” control & “InputFormControl” are SharePoint controls that creates the standard look and feel that SharePoint forms have.  So, with those encasing my control (made up of labels, textboxes, dropdowns etc), I end up with something like this:
 

(click to see an image that is not squashed down)
 
 
Great, so now I need to put together the code that is going to be associated with this control.  All this code really needs to do is to create the correct DelimitedPropertyString for the values set by the user in the control.  So (for example) if they have checked a checkbox, put a “True;” in the delimited string.
 
I have a little logic around the “Load Lists” functionality – I want the user to enter a url to a SharePoint site containing the list holding the tree data, to then click a button to load the lists on this site into a dropdown, and finally to select which specific list holds the tree data.  I ensure that the path to the site is a relative url by removing the root url for the current web application if it exists in the given site url.
 
The OnSaveChange method is used to create a delimited string for all the properties, and then set this string against the controls “DelimitedPropertyValues” property.
 
So that we set these controls to have the correct values when someone is editing an existing TreeList column, the InitializeWithField method must parse the “DelimitedPropertyValues” string and set to

Advertisements

2 thoughts on “Adding a Tree Control column to SharePoint

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