I like to follow what’s going on on the SharePoint forums and one of the things I’ve noticed is that practically every day somebody starts a thread about RenderPatterns. Either they’ve created a custom field and they want to know how to use RenderPatterns or they’ve read through the documentation, have created a RenderPattern and it doesn’t do what they expect. I thought I’d spend a bit of time documenting my findings with regard to rendering of custom fields and in particular the elusive RenderPattern.
The Documentation
We’ll start with the MSDN documentation since anybody looking to build a custom field is probably already familiar with this: http://msdn.microsoft.com/en-us/library/aa544291.aspx
One of the key things to be aware of here is that whenever you’re displaying your data in a list, the only thing that matters is the DisplayPattern CAML. The documentation suggests that you can create a rendering template or even build your own rendering control but neither of these techniques works when displaying your data in a list. We’ll get into the reasons for that later, but I just thought I’d make that clear up front because I don’t think it’s obvious from the documentation.
The Field Definition
When creating a custom field you’ll define a field definition in a file called fldtypes_myfieldname.xml, It’ll probably look something like this:
<fieldtype>
<field name="TypeName">TestTextField</field>
<field name="ParentType">Text</field>
<field name="InternalType">Text</field>
<field name="TypeDisplayName">TestTextField</field>
<field name="TypeShortDescription">Description for TestTextField</field>
<field name="UserCreatable">TRUE</field>
<field name="Sortable">TRUE</field>
<field name="AllowBaseTypeRendering">TRUE</field>
<field name="Filterable">TRUE</field>
<field name="FieldTypeClass">SpFieldTest.TestTextField, SpFieldTest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=8af7048eb6ec79b4</field>
<propertyschema>
<fields>
<field name="MyCustomProperty" hidden="TRUE" displayname="My Custom Property" type="Text">
<default>My Default</default>
</field>
</fields>
</propertyschema>
<renderpattern name="HeaderPattern">
<property select="DisplayName" htmlencode="TRUE"></property>
</renderpattern>
<renderpattern name="DisplayPattern">
<column />
</renderpattern>
</fieldtype>
There are a few things to be aware of when creating field definitions:
- Setting the ParentType is optional, if you do set it then effectively your field inherits it’s rendering configuration from the parent type. So unless you override the RenderPatterns, the patterns from the parent will be used. (When it comes to programmatically manipulating the field via an inherited SPField object the ParentType doesn’t make any difference but we’ll cover that later)
- If you do set a parent type, it must be valid. If you enter a parent type that’s invalid your control won’t render in a list even if you include a valid DisplayPattern. (You can tell is that’s the problem because your field won’t display a header in the list either). Valid parent types can be found in fldtypes.xml and other files that are named fldtypes_<Whatever>.xml in the ….web server extensions\12\TEMPLATE\XML folder. The base field types include:
| Counter |
Text |
Note |
Choice |
MultiChoice |
| GridChoice |
Integer |
Number |
ModStat |
Currency |
| DateTime |
Lookup |
Boolean |
Threading |
ThreadIndex |
| Guid |
Computed |
File |
Attachments |
User |
| URL |
Calculated |
Recurrence |
CrossProjectLink |
ContentTypeId |
| MultiColumn |
LookupMulti |
UserMulti |
WorkflowStatus |
AllDayEvent |
| WorkflowEventType |
PageSeparator |
- If you don’t set a parent type you must include a HeaderPattern. If you don’t you’ll see something like this (not sure if the message is localised):
- If you don’t specify a parent type, you must specify an InternalType. Valid values for InternalType are the same as those for ParentType. You can specify both ParentType and InternalType, but InternalType is ignored if ParentType is set. If you don’t specify either you’ll get an System.Runtime.InteropServices.COMException: Exception occurred. (Exception from HRESULT: 0x80020009 (DISP_E_EXCEPTION)) message.
- Neither ParentType nor InternalType are case sensitive.
The SPField Object
If you’re creating a custom field you’ll have created a new object that’s derived directly or indirectly from SPField. The documentation covering this object and how it all works is pretty good so I don’t have much to add except one important thing:
The parsing of a RenderPattern does not use your SPField object. It doesn’t matter what you override you’ll never get a debugger to stop in your object when rendering a list view because SPField isn’t used.
The RenderPattern
To properly understand the RenderPattern it’s worthwhile considering a bit of history. Back in the early days of SharePoint, Xslt wasn’t what it is today and so the good folks at Microsoft came up with CAML as an xml-based means of formatting data for SharePoint. Back then SharePoint Team Services didn’t have the whistles and bells that it does today but one of the things it did do was display custom data in a list on a web page and it did that by parsing the CAML definitions for each field. Today this behaviour is implemented by the SPList object’s RenderAsHtml method.
As you’ll see from the documentation(and probably know from bitter experience!), the actual mechanism behind RenderAsHtml isn’t apparent. The problem with this lack of information is that we have no way to know exactly how the CAML in our RenderPattern will be processed.
Here’s what I’ve been able to figure out by performing some black box testing:
- Behind the scenes the RenderAsHtml method calls owssvr.dll?Cmd=RenderView
- The way in which CAML is parsed is dependent on the type of field you’ve created. By type I’m referring to ParentType/InternalType in your field definition not the type of your SPField-based object. Certain CAML elements such as <LookupColumn> only work properly if your field is of type “Lookup” for example.
- The properties that are available via the <Property> element vary depending on the type. I’ve been unable to find out which properties are available for each type. I suspect this is hard coded inside owssvr.dll.
- The property type in your field definition governs the base SPField type that your custom field will be cast to when using the new or edit form. (So if you set the type to Lookup in your field definition but actually derive your custom field from SPFieldText, you’ll see an error when you try to edit or add)
Conclusion
RenderPatterns are old school, in fact they’re so old school that I suspect there’s no decent documentation because the folks that wrote the code behind it have all retired! Unfortunately we’re stuck with them in SharePoint 2007 and by the looks of it in SharePoint 2010 as well. So what can be done to give us back the control we need?
Edit 2 Feb 2010: SharePoint 2010, although it still supports the use of the ListViewWebPart and the underlying CAML madness, by default, when the UI is in v4 mode all lists are rendered using XSLT.
By default all lists and document libraries are rendered using the ListVieWebPart, this makes use of the problematic functionality described above. Thankfully, it doesn’t have to be this way. One easy way to get back control is to replace the ListViewWebPart with a DataFormWebPart.
You can easily do that in SharePoint Designer by navigating to your list, opening the aspx page that stores your view, right clicking on the ListViewWebPart and selecting the Convert to XSLT Data View option:
Hopefully this post gives a bit more detail on rendering for custom fields and saves you some time wading through the documentation on to find that the answer isn’t there. As always, comments/complaints/criticisms and questions are always welcome.
Edit 2 Feb 2010: Added a bit more info on a separate post - http://www.chaholl.com/archive/2010/02/02/disentangling-render-patterns.aspx
posted @ Saturday, November 07, 2009 4:32 PM