Friday, May 3, 2013

SharePoint 2010 Forms Templates

In this article I'll tell you how to change standard templates for Edit, Display and New Forms for List Items and Documents in Sharepoint 2010. You can make it with SharePoint Designer or InfoPath for partucular lists. This is described here:
But what if you need to change all forms of templates in the farms with your custom form through wsp-package? While I was investigating this question I found many suggestions to change file 14\TEMPLATE\CONTROLTEMPLATES\DefaultTemplates.ascx:

This template is used for default list edit, display and to create form of list items:
<SharePoint:RenderingTemplate id="ListForm" runat="server">  <Template></Template></SharePoint:RenderingTemplate>

And this one is used for documents:
<SharePoint:RenderingTemplate id="DocumentLibraryForm" runat="server">  <Template></Template></SharePoint:RenderingTemplate>
Yes, if you change these templates and make iisreset you'll get what you want — a new template for all forms.  So, what if we don't want to change the system files? Okey, let's look at the control, that manages templates inCONTROLTEMPLATES folder: SPControlTemplateManager. The method GetTemplateByName(String) of this class returns the template of RenderingTemplatecontrol by its ID. All templates are loaded to the static HASH-table after the first call of this method. That is why we should make iisreset after changing DefaultTemplates.ascxfile. So let's see how it works:

private static Hashtable GetTemplateCollection()
{
    if ((s_templateTable == null) && (HttpContext.Current != null))
    {
        lock (InternalSyncObject)
        {
            if (s_templateTable == null)
            {
                Hashtable templateTable = new Hashtable();
                FileInfo[] files = new DirectoryInfo(
                  HttpContext.Current.Server.MapPath(systemTemplateLocation)).GetFiles("*.ascx");
                string controlTemplateFile = systemTemplateLocation + defaultTemplateFile;
                string str3 = systemTemplateLocation + mobileDefaultTemplateFile;
                LoadControlTemplate(templateTable, controlTemplateFile);
                LoadControlTemplate(templateTable, str3);
                foreach (FileInfo info2 in files)
                {
                    if (!(info2.Name == defaultTemplateFile) && !(info2.Name == mobileDefaultTemplateFile))
                    {
                        controlTemplateFile = systemTemplateLocation + info2.Name;
                        LoadControlTemplate(templateTable, controlTemplateFile);
                    }
                }
                s_templateTable = templateTable;
            }
        }
    }
    return s_templateTable;
}

Variables values:
  • systemTemplateLocation = "/_controltemplates/";
  • defaultTemplateFile = "DefaultTemplates.ascx";
As you see, first, this control loads all templates from DefaultTemplates.ascxfile. Then it gets all files formCONTROLTEMPLATES directory and loads all templates from them. So if it finds templates with the same name as defined in DefaultTemplates.ascx it replaces them. Okey, let’s check it. Create a new file in CONTROLTEMPLATEdirectory and add a template to it:

<SharePoint:RenderingTemplate id="ListForm" runat="server"> 
  <Template>    <h1>Custom form!</h1>  </Template></SharePoint:RenderingTemplate>

Make iisreset, navigate  some list and try to create a new item. You'll see our title instead of form. Okey, it  works perfectly for standard templates, but what if we want to change the template for only one Web Application or SiteCollection or change the template for DocumentSet display form, which stores its template in fileDocSetTemplates.ascx. Let's look at ListFormWebPart. This class has property TemplateName which is used to get a template name by current context (Edit, Create or Display):
public string TemplateName
{
    get
    {
        if (this.templateName == null)
        {
            this.EnsureListAndForm();
            if (this.ItemContext != null)
            {
                SPContentType contentType = this.ItemContext.ContentType;
                if (contentType != null)
                {
                    switch (this.pageType)
                    {
                        case PAGETYPE.PAGE_DISPLAYFORM:
                            this.templateName = contentType.DisplayFormTemplateName;
                            break;

                        case PAGETYPE.PAGE_EDITFORM:
                            this.templateName = contentType.EditFormTemplateName;
                            break;

                        case PAGETYPE.PAGE_NEWFORM:
                            this.templateName = contentType.NewFormTemplateName;
                            break;
                    }
                    if ((this.templateName != null) && (this.templateName.Length > 0))
                    {
                        return this.templateName;
                    }
                }
            }
            if (this.form != null)
            {
                this.templateName = this.form.TemplateName;
            }
            else
            {
                this.templateName = "ListForm";
            }
        }
        return this.templateName;
    }
    set
    {
        this.templateName = value;
    }
}

To get the name of the templates it uses properties of ContentType: DisplayFormTemplateName,EditFormTemplateNameNewFormTemplateName. So, we can create a new template in CONTROLTEMPLATESdirectory and set its name into all content types we need with powershell, for example. If we remove our template nothing happens, because if the template is not found it uses a default ListForm template.

No comments:

Post a Comment