A main criterion that distinguishes websites between good and bad usability is the way, how users can enter data to forms. 
Imagine a list with 
around 15 or more fields. Now a user creates an initial item for that he
 only enters a few metadata to the item like title, description and a 
date. After that, another user modifies that item and adds some other 
field-values. And at last but not least, a third user completes the form
 by entering all missing values. So you want to show specific fields 
related to users or roles. Wrap that by a workflow with 
email-notifications if you want but that’s not the topic of my post. 
By default, you have a 
newform.aspx/editform.aspx that displays all those 15 fields which is 
not quite necessary for the first user. The second user should not see 
those metadata-fields the first user entered during initial creation and
 the last user fills the last values.
Finally you really want 
to impress your customer so the fields in the form are grouped by 
context in a multi-columned table and have some stylish images around.
So how would you do that
 without creating your own applicationpage with onClick-eventhandling on
 the submit-button and managing saving all the field-values to the item 
by your own?
“Use custom form templates!” is the answer.
So how do we do that?
At first, it’s important
 to know that the default-template that’s displayed if you enter the 
NewForm.aspx or the EditForm.aspx is called ListForm and can be found in 14-Hive\TEMPLATE\CONTROLTEMPLATES\DefaultTemplates.ascx.
In that RenderingTemplate the typical design you know from the xxxForm.aspx is rendered here. Pay attention to the WebControl  
 which renders all visible fields from the list by iterating them. MSDN 
says you can inherit from the ListFieldIterator and create your own 
FieldIterator-Class. We don’t want that. We write our own 
RenderingTemplate.
For this experiment, I 
created a new Blank Site Collection with english language where I set my
 upcoming project to. Create a new Empty SharePoint Project in your Visual Studio 2010 and set its destionation Site Url to the just created Site Collection. Now add an item Content Type to your project and set Item as base content type. Now add an item Empty Element named “fields” to that content type.
![]()  | 
This is our project structure so far 
 | 
In its Elements.xml we add some fields that we want to use in our list later:
 <Field ID="{42DEFD29-4A11-4fd7-958A-137049381E53}"
Name="TestTextfeld"
StaticName="TestTextfeld"
DisplayName="TestTextfeld"
Type="Text"/>
<Field ID="{3B6982AF-7B93-4b3c-95BB-3D90E03E30EC}"
Name="TestDatetime"
StaticName="TestDatetime"
DisplayName="TestDatetime"
Format="DateOnly"
Type="MyDateTimeField"/>
<Field ID="{B3C1A58F-9583-410d-BA4B-5545E37565F1}"
Name="TestBoolean"
StaticName="TestBoolean"
DisplayName="TestBoolean"
Type="Boolean"/>
<Field ID="{273D7F41-BB9D-4537-AF66-477A0FA09CC9}"
Name="TestChoice"
StaticName="TestChoice"
DisplayName="TestChoice"
Type="Choice">
<CHOICES>
<CHOICE>1</CHOICE>
<CHOICE>2</CHOICE>
<CHOICE>3</CHOICE>
</CHOICES>
</Field>
<Field ID="{EB57DC41-A510-442a-83DE-09D01462914E}"
Name="TestUserField"
StaticName="TestUserField"
DisplayName="TestUserField"
Type="User"/>
</Elements>
After that, reference those fields in your ContentType. Your Elements.xml now should look like this:
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<!-- Parent ContentType: Item (0x01) -->
<ContentType ID="0x01000db7705609a14adeacf933a7ce690bb8"
Name="SharePointProject1 - ContentType1"
Group="Custom Content Types"
Description="My Content Type"
Inherits="FALSE"
Version="0">
<FieldRefs>
<FieldRef ID="{42DEFD29-4A11-4fd7-958A-137049381E53}" Name="TestTextfeld"/>
<FieldRef ID="{3B6982AF-7B93-4b3c-95BB-3D90E03E30EC}" Name="TestDatetime"/>
<FieldRef ID="{B3C1A58F-9583-410d-BA4B-5545E37565F1}" Name="TestBoolean"/>
<FieldRef ID="{273D7F41-BB9D-4537-AF66-477A0FA09CC9}" Name="TestChoice"/>
<FieldRef ID="{EB57DC41-A510-442a-83DE-09D01462914E}" Name="TestUserField"/>
</FieldRefs>
</ContentType>
</Elements>
Now comes the cool part: after the closing </FieldRef>-Tag add this xml-snippet:
<XmlDocuments>
<XmlDocument NamespaceURI="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms">
<FormTemplates xmlns="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms">
<Display>ListForm</Display>
<Edit>CType1CustomForm</Edit>
<New>CType1CustomForm</New>
</FormTemplates>
</XmlDocument>
</XmlDocuments>
CType1CustomForm is the 
new RenderingTemplate we want to use for edit and new. Display we do 
ignore for the moment; show the item in the default way by ListForm. It’s important to set the Inherits-Attribute
 to FALSE or the custom form templates are ignored, no matter, what you 
enter here. If you need to inherit from another content type, you also 
can set the formTemplates by code, for e.g. in a Feature Receiver:
SPContentType ctype = spWeb.ContentTypes[new SPContentTypeId("0x01000db7705609a14adeacf933a7ce690bb8")];
ctype.NewFormTemplateName = "CType1CustomForm";
ctype.EditFormTemplateName = "CType1CustomForm";
ctype.Update(true);
ctype.NewFormTemplateName = "CType1CustomForm";
ctype.EditFormTemplateName = "CType1CustomForm";
ctype.Update(true);
Pay attention that the approach of setting custom templates to each content types makes it possible to individualize the form for every content type in your list. No more inappropriate fields. :-)
So now it’s time to create the Template. Add a new SharePoint Mapped Folder and set it to {SharePointRoot}\TEMPLATE\CONTROLTEMPLATES.
Add
 a new User Control to this folder and remove its .cs-Files.  In my 
example, I named it CType1CustomForm.ascx. From the SharePoint 
DefaultTemplate.ascx (found in 14-Hive\TEMPLATE\CONTROLTEMPLATES) I copied that Part beginning with <SharePoint:RenderingTemplate id="ListForm" runat="server"> and ending with </SharePoint:RenderingTemplate>  into the new user control.  
To proof, that now this Template is used by our content type, I added the Term “CType1CustomForm” after the <span id='part1'>-Tag which is displayed first in the dialog’s contentarea.
To proof, that now this Template is used by our content type, I added the Term “CType1CustomForm” after the <span id='part1'>-Tag which is displayed first in the dialog’s contentarea.
<ListInstance Title="SharePointProject1 - ListInstance1"
OnQuickLaunch="TRUE"
TemplateType="10000"
Url="Lists/SharePointProject1-ListInstance1"
Description="My List Instance">
<Data>
<Rows>
<Row>
<Field Name="TestTextfeld">Text im Textfeld</Field>
<Field Name="TestDatetime">2010-10-28T11:00:00Z</Field>
</Row>
</Rows>
</Data>
</ListInstance>
If
 you want, you can test the progress so far by pressing F5 and click 
“Add new item” in the list. You should see something like this:
Okay, the half of the job is done. Now we want to rearrange the lame display of the fields.
For
 that purpose, add another User Control to the mapped 
CONTROLTEMPLATES-folder but this time leave all the automatically 
created Code-Behind-Files. In my case, I named it MyCustomForm.ascx.
<SharePoint:FolderFormFields ID="FolderFormFields1" runat="server"/>
<!-- myCustomForm -->
<myCustomForm:AddForm runat="server" />
<!-- myCustomForm -->
<SharePoint:ListFieldIterator ID="ListFieldIterator1" runat="server"/>
<!-- myCustomForm -->
<myCustomForm:AddForm runat="server" />
<!-- myCustomForm -->
<SharePoint:ListFieldIterator ID="ListFieldIterator1" runat="server"/>
Don’t forget to register the tag in the directives-area:
<%@ Register TagPrefix="myCustomForm" TagName="AddForm" src="~/_controltemplates/MyCustomForm.ascx" %>  
All
 the fields, which are added in MyCustomForm.ascx will not be rendered 
by the ListFieldIterator again. But if your customer adds new fields to 
the list after you installed the solution, those new fields are rendered
 fine like the default-forms below your customizations.
Now let’s come to the MyCustomForm.ascx. 
In this User template, I created a HTML-Table where I placed all the SharePoint-WebControls to render the fields, for e.g:
<table width="700px">
<tr>
<td>
<asp:Label ID="Label5" runat="server" Text="Title" />
</td>
<td>
<SharePoint:TextField ID="Title" runat="server" FieldName="Title" />
</td>
<td>
</td>
<td>
<asp:Panel ID="bild" runat="server"></asp:Panel>
</td>
</tr>
<tr>
<td>
<asp:Label ID="Label1" runat="server" Text="Textfeld" />
</td>
<td>
<SharePoint:TextField ID="TextField1" runat="server" FieldName="TestTextfeld" />
</td>
<td>
<asp:Label ID="Label2" runat="server" Text="Datetime" />
</td>
<td>
<SharePoint:DateTimeField ID="DateTimeField1" runat="server" FieldName="TestDatetime" />
</td>
</tr>
<tr>
<td>
<asp:Label ID="Label6" runat="server" Text="Userfeld" />
</td>
<td>
<SharePoint:UserField ID="UserField" runat="server" FieldName="TestUserField" />
</td>
<td></td>
<td></td>
</tr>
<tr>
<td>
<asp:Label ID="Label3" runat="server" Text="Boolean"/>
</td>
<td>
<SharePoint:BooleanField runat="server" FieldName="TestBoolean" ID="booleanField" /> (Check this box to see more settings)
</td>
<asp:TableCell ID="choiceLabel" runat="server">
<asp:Label ID="Label4" runat="server" Text="Choice"/>
</asp:TableCell>
<asp:TableCell ID="choiceField" runat="server">
<SharePoint:RadioButtonChoiceField ID="RadioButtonChoiceField1" runat="server" FieldName="TestChoice" />
</asp:TableCell>
</tr>
</table>
As
 you can see, it’s quite simple to add the field controls. It’s 
important, to set the correct FieldName. If the FieldName-Values doesn’t
 match the internal fieldnames, SharePoint can’t map them and displays 
the control by the ListFieldIterator instead of your code.
You
 can also use your own custom fields here. To demonstrate, I created a 
new custom field by inheriting from the default DateTime-field to show 
the user an error-message, if the entered date is lower than the current
 date. Because my custom field inherits from SPFieldDateTime, I can 
display it by using 
<SharePoint:DateTimeField ID="DateTimeField1" runat="server" FieldName="TestDatetime" />
In
 the wired CodeBehind I added some functionality to toggle the 
visibility of the radiobuttons-field depending on the checkbox-state. 
Don’t be worried, to provide you a sum of all the written above, I 
attach the sourcecode for download below.
Following a picture of the final result:
As
 you can see, the content of the NewForm/EditForm is completely 
different from the default-style. As I described earlier, the 
ListFieldIterator adds new not referenced fields below until you update 
the user control:
Hint:
 If you get an exception during F5-debugging when you entered an invalid
 date, like you can see on the following screen, just ignore it by 
hitting the run-button. It seems like this way (throwing an exception on
 field-validation) is the Microsoft-preferred way to handle invalid 
field-values:
The exception-message is the red-displayed error-message below the validated field.





Comments
Post a Comment