For my Event Receiver’s post I had to do some more investigation on how the List Forms work and I thought it will be a good idea to put together my findings. As you know each list has 3 forms – one for creating a new item, one for editing an existing item and one for displaying an exiting item.
The first place where those forms are defined is in the List schema xml. In SharePoint 2003 (WSS 2.0) the forms used to be defined using a complex CAML but from SharePoint 2007 (WSS 3.0) they are implemented in ASPX pages using web controls. The Form element in the List schema xml is used to define the aspx page to be used for the given List Form and by default most lists use NewForm.aspx, EditForm.aspx and DistForm.aspx pages.
If necessary the aspx pages for the List forms can be redefined per item content type. This can be achieved by including a FormUrls XmlDocument with your custom content type.
So sfter SharePoint has determined from the List schema xml and the ContentType FormUrls element which aspx page should be used it opens up that page. Each of those pages contain a ListFormWebPart which does all the job of rendering the list item. SharePoint 2007 still supports legacy forms and you can use the UseLegacyForm attribute of the Form element in the List schema xml to tell SharePoint you want to use the CALM forms. In such a case the rendering of the List Form will be done from the unmanaged SPRequest class, which will return the HTML to be rendered.
In most of the cases no legacy forms are used and then the ListFormWebPart needs to determine which Form Template has to be used with the List Form. The Form Templates provide a way to further customize the list forms without changing the aspx pages. This is what SharePoint does as it uses exactly the same NewForm.aspx page for all new forms but uses different Form Templates for a standard list and for a document library. The Form Templates also allow to customize the list forms for items in the same list but for different content types.
The Form Templates are defined as an XmlDocument per content type and all content types that inherit from the Item content type also inherit the Form Templates as defined in the Item Content Type. All forms use a Form Template called ListForm.
However not all forms in SharePoint use these Form Templates. For example they are redefined by the Document content type (and all content types that inherit from Document) and they use a Form Template called DocumentLibraryForm instead of ListForm.
The next question is where those Form Templates come from and the answer is they usually come from the 12\TEMPLATE\CONTROLTEMPLATES\DefaultTemplates.ascx page. The form templates are simply RenderingTemplate web controls and define the sets of controls to be added to the List Form. The Form Templates are matched by their ID attribute and it is actually possible to overwrite an existing template or define your own Form Templates and deploy them in an ascx page in 12\TEMPLATE\CONTROLTEMPLATES.
The code below shows the standard ListForm templates used by all generic lists:
<SharePoint:RenderingTemplate ID=”ListForm” runat=”server”>
<SharePoint:InformationBar ID=”InformationBar1″ runat=”server”/>
<wssuc:ToolBar CssClass=”ms-formtoolbar” id=”toolBarTbltop” RightButtonSeparator=” ” runat=”server”>
<SharePoint:NextPageButton ID=”NextPageButton1″ runat=”server”/>
<SharePoint:SaveButton ID=”SaveButton1″ runat=”server”/>
<SharePoint:GoBackButton ID=”GoBackButton1″ runat=”server”/>
<SharePoint:FormToolBar ID=”FormToolBar1″ runat=”server”/>
<TABLE class=”ms-formtable” style=”margin-top: 8px;” border=0 cellpadding=0 cellspacing=0 width=100%>
<SharePoint:ChangeContentType ID=”ChangeContentType1″ runat=”server”/>
<SharePoint:FolderFormFields ID=”FolderFormFields1″ runat=”server”/>
<SharePoint:ListFieldIterator ID=”ListFieldIterator1″ runat=”server”/>
<SharePoint:ApprovalStatus ID=”ApprovalStatus1″ runat=”server”/>
<SharePoint:FormComponent ID=”FormComponent1″ TemplateName=”AttachmentRows” runat=”server”/>
<table cellpadding=0 cellspacing=0 width=100%><tr><td class=”ms-formline”><IMG SRC=”/_layouts/images/blank.gif” width=1 height=1 alt=””></td></tr></table>
<TABLE cellpadding=0 cellspacing=0 width=100% style=”padding-top: 7px”><tr><td width=100%>
<SharePoint:ItemHiddenVersion ID=”ItemHiddenVersion1″ runat=”server”/>
<SharePoint:ParentInformationField ID=”ParentInformationField1″ runat=”server”/>
<SharePoint:InitContentType ID=”InitContentType1″ runat=”server”/>
<wssuc:ToolBar CssClass=”ms-formtoolbar” id=”toolBarTbl” RightButtonSeparator=” ” runat=”server”>
<SharePoint:CreatedModifiedInfo ID=”CreatedModifiedInfo1″ runat=”server”/>
<SharePoint:SaveButton ID=”SaveButton2″ runat=”server”/>
<SharePoint:GoBackButton ID=”GoBackButton2″ runat=”server”/>
<SharePoint:AttachmentUpload ID=”AttachmentUpload1″ runat=”server”/>
You can probably recognize all the controls you have seen many times in those NewForm.aspx pages. There are many “interesting” controls in that form, such as the ListFieldIterator, InitContentType, SaveButton, AttachmentUpload. A detailed information on how to customize your ListForms, include custom fields and customize the Form Templates could be found in the following MSDN article.
Issues with Document Libraries and _layouts/Upload.aspx
There is one specific issue when using a NewForm with a ListFormWebPart in a Document Library. You will be unconditionally redirected to the _layouts/Upload.aspx page so you can upload the file first. After the file is uploaded you will be redirected to the EditForm. So what does this mean:
- Well first of all the “List Form” and “Form Template” of the NewForm are actually not used because you will be unconditionally redirected to the Upload.aspx page. Of course you have the alternative of creating a custom New Form that _does not_ contain a ListFormWebPart. However all the SharePoint Field controls require to be inside a ListFormWebPart so you won’t be able to use those. You can actually use the SharePoint Field controls without a ListFormWebPart but you will need to create a new SPContext object in the Page.OnInit() event using reflection and set the ItemContext property of the SharePoint Field web control. No need to say that this will probably not be supported by Microsoft.
- Secondly the ItemAdded and ItemAdding event receivers will be initiated from the Upload.aspx page after the file is uploaded and a blank list item has been created. However this happens before you are redirected to the Edit Form and before the user has filled in the metadata of the document. Even worse the ItemAdded event receiver is executed asynchronously and there is no guarantee when it will be run. Depending on how loaded is the server and how quick the user clicks “Check In” on the Edit Form, the ItemAdded event receiver can be actually executed after the Edit Form has been submitted! Also if you rely the ItemAdded event receiver to set some default values for the item after it has been created, which values you expect to be displayed in the Edit Form, it is quite possible that the ItemAdded will be executed after the Edit Form has rendered the old values of the item (before they have been changed by the event receiver).
- Lastly if you press “Cancel” on the Edit Form after the file has been already uploaded the file and the list item may remain in a strange state where it is only visible to the person who has uploaded the file and is even not visible to the system account. This happens when the document library is in a “Force Check Out” mode. See more in this post.