This post is the first out of a two-part series, where I look at the way SharePoint list forms work and how we can customise them. Part 1 explains how to use custom ASPX pages for list forms, and Part 2 goes through replacing SharePoint’s default rendering templates with custom ones. At the end of the activity I will provide a code sample with both.
When we provision a list in SharePoint we make an ‘instance’ of it based on a list template. Templates are defined in features, and each feature with a list template will hold a schema.xml file. You can view the schema.xml files of existing list templates in features that come with WSS – CustomList, ContactList, DocumentLibrary, etc. just check the 12\TEMPLATE\FEATURES folder.
At the bottom of the schema.xml files we can see a Form element that defines the ASPX files used during the provisioning of lists:
When a list is provisioned, the platform makes a copy of the physical file defined in the “SetupPath” attribute, stores it in the content DB and names it as specified in the “Url” attribute, and adds a ListFormWebPart to the WebPartZoneID specified. “pages\form.aspx” maps to 12\TEMPLATE\Pages\form.aspx and you could replace these with your own. I have demonstrated CustomList, but other lists and libraries use the rest of the files in there.
All this gets interesting when Content Types are added to lists. Each Content Type can have its _own_ DisplayForm, EditForm or NewForm – and in a single list you can have different forms for different Content Types - This means POWER! Furthermore, the same Content Types used across different lists can have consistent forms.
So how does it work?
The SPContentType class allows you to set the EditFormUrl, DispFormUrl, and NewFormUrl properties:
cType.EditFormUrl = "_layouts/ourprojectfolder/customedit.aspx";
cType.NewFormUrl = "_layouts/ourprojectfolder/customnew.aspx";
cType.DisplayFormUrl = "_layouts/ourprojectfolder/customdisplay.aspx";
If these are set, this is what happens under the hood:
· The “New” button on the toolbar or the Item Context menu takes the user to one of the forms: EditForm.aspx, NewForm.aspx or DispForm.aspx
· During provisioning, the ListFormWebPart is added to each of these forms. Check the WebPartZoneID property – this tells the platform where to add the web part. You can’t go without it – SharePoint complains.
· The ListFormWebPart checks the current SPControlMode (Edit, New, Display) and whether the respective property of the current item’s Content Type is null or empty. This can be seen by examining the source code of the web part with Reflector. It makes a check on this.FormPageUrl (which is obfuscated!):
So what we can see is the navigation items take us to either NewForm.aspx, EditForm.aspx or DispForm.aspx. The ListFormWebPart on that page does a check on the current Content Type and takes us to the current SPControlMode’s form. This is what “this.FormPageUrl” does behind the “obfuscated” scene.
An obvious drawback of such design is the fact that the user is first taken to NewForm.aspx (or any of the others), then an SPUtility.Redirect call is made (essentially Response.Redirect) which results in a second postback for the user. You can see the two requests with Firebug or any other HTTP listener. Apart from that there is some overhead – NewForm.aspx is a web part page (and they aren’t light).
What I currently don’t know is how to set the EditFormUrl, NewFormUrl and DispFormUrl properties in the ContentType definition schema. The “Forms” element is obsolete in WSS v3, so the only current way I know to change forms via CAML is to work with the XmlDocuments element. These two options work in a completely different manner. In Part 2 of this series I will demonstrate how you can set custom rendering templates in features with content types.
Hope this helps.