SharePoint Internals – Hristo Pavlov’s Blog

17 February, 2009

Understanding SharePoint: List Forms

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.

 <FormTemplates xmlns=”http://schemas.microsoft.com/sharepoint/v3/contenttype/forms”&gt;

    <Display>ListForm</Display>

    <Edit>ListForm</Edit>

    <New>ListForm</New>

</FormTemplates>

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

listforms

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”>

      <Template>

            <SPAN id=’part1′>

                  <SharePoint:InformationBar ID=”InformationBar1″ runat=”server”/>

                  <wssuc:ToolBar CssClass=”ms-formtoolbar” id=”toolBarTbltop” RightButtonSeparator=”&nbsp;” runat=”server”>

                              <Template_RightButtons>

                                    <SharePoint:NextPageButton ID=”NextPageButton1″ runat=”server”/>

                                    <SharePoint:SaveButton ID=”SaveButton1″ runat=”server”/>

                                    <SharePoint:GoBackButton ID=”GoBackButton1″ runat=”server”/>

                              </Template_RightButtons>

                  </wssuc:ToolBar>

                  <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>

                  <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=”&nbsp;” runat=”server”>

                              <Template_Buttons>

                                    <SharePoint:CreatedModifiedInfo ID=”CreatedModifiedInfo1″ runat=”server”/>

                              </Template_Buttons>

                              <Template_RightButtons>

                                    <SharePoint:SaveButton ID=”SaveButton2″ runat=”server”/>

                                    <SharePoint:GoBackButton ID=”GoBackButton2″ runat=”server”/>

                              </Template_RightButtons>

                  </wssuc:ToolBar>

                  </td></tr></TABLE>

            </SPAN>

            <SharePoint:AttachmentUpload ID=”AttachmentUpload1″ runat=”server”/>

      </Template>

</SharePoint:RenderingTemplate>

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.

Advertisements

30 April, 2008

EditForm.aspx not shown when uploading a document

Filed under: SharePoint — Tags: , , , , , — hristopavlov @ 7:56 am

I was working on this SharePoint solution where we have a whole bunch of content types, site columns and feature receivers that are adding content types to document libraries on the fly. We were doing this because the client didn’t want to use list instances in the site definitions.

So I had this very bizzare issue when in some document libraries when I was uploading a document the edit form was not shown at all. So I choose “Upload”, browse to a file, hit “OK” and instead of getting the edit form to fill in the metadata I was getting redirected to the default view of the list. The file was being uploaded successfully but the user couldn’t change the metadata during the upload. And this was happening only on some document libraries but not on others.

A quick look to the SchemaXML of some of the libraries with SharePoint Explorer revealed that the document libraries that were having the problem were missing the “Folder” content type. And unfortunately you cannot see this content type from the UI so from the UI all of the libraries were looking the same. However I could browse for the “Folder” content type and add it to my library. After doing this with the problem was resolved and the edit form was being shown once again …

Determined to find out the root of this strange behaviour I checked the code of the Upload.aspx page in the 12 hive and it releaved the code behind class used by the page:

<%@ Assembly Name=”Microsoft.SharePoint.ApplicationPages, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c”%>

<%@ Page Language=”C#” Inherits=”Microsoft.SharePoint.ApplicationPages.UploadPage” MasterPageFile=”~/_layouts/application.master” %>

I then started Reflector and checked what happens when the user hits “Submit”. An excerpt is shown below

protected void OnSubmit(object o, EventArgs e)

{

    if (!this.MultipleUploadMode)

    {

        …

 

        if ((!this.IsSimpleList || (spfile.CheckOutStatus != SPFile.SPCheckOutStatus.None)) && (spfile.Item != null))

        {

            SPUtility.Redirect(this.GetEditFormUrl(spfile), SPRedirectFlags.Default, this.Context);

            return;

        }

 

        …

 

    }

}

   

As the code shows the user is only redirected to the edit form if the file is checked out or if the document library is not a “Simple List”. Checking the code of the IsSimpleList property showed that “Simple Lists” are lists that have only one content type and don’t have their “Title” field marked as “ShowInEditForm” = “FALSE”

In my case when the “Folder” content type was not present the document library was having only one content type and was qualifying as a “Simple List” and as a result the edit form was not shown when uploading a document!

So what’s the moral of the story … well I guess don’t delete the “Folder” content type from your document libraries

Blog at WordPress.com.