Customizing List Item Forms in Windows SharePoint Services

 

Les W. Smith
Microsoft Corporation

March 2005

Applies to:
    Microsoft Windows SharePoint Services

Summary: Enhance and extend interaction with lists in Microsoft Windows SharePoint Services when customizing forms used to work with list items. (34 printed pages)

Contents

Introduction to Customizing List Forms
SharePoint List Definitions
List Item Form Page Layout
Form View Definition
Creating a Custom Site Definition
Adding Left Navigation to a Form Through Web Server Controls
Embedding a Web Part in a Form and in the Home Page to Display List Data
Creating a Form to Extend the Reach of a Survey
Advanced Customizations
Conclusion
Additional Resources

Introduction to Customizing List Forms

In Microsoft Windows SharePoint Services, you use list item forms to create, modify, or display individual items in the SharePoint list. In this article, we explore best practices for customizing list item forms in Windows SharePoint Services, the layout of the SharePoint page containing a form, and the underlying XML Schema that defines the form's content. By working through a few common tasks, you can understand ways to extend the reach and functionality of forms for interacting with SharePoint lists. We provide examples of common customizations such as adding links to the form's left navigational area, displaying list data in a form, or displaying a form in the home page. We also provide examples of advanced customizations such as customizing the toolbar or body in a form, or adding script to interact with user clicks and to validate data.

We focus on customizations you can perform in the following areas:

  • The ASPX page that contains the list item form
  • XML Schema files that define list item form fields and form views
  • Custom Web server controls and custom Web Parts that consolidate code and implement types and members of namespaces in the Windows SharePoint Services assembly to extend user interaction with list data

SharePoint List Definitions

When you create a list in a SharePoint site, Windows SharePoint Services generates the list instance from a list definition contained in the site definition, from which the site was created. Each list draws its definition from files that apply globally to the site, such as the following:

  • ONET.XML specifies the fields included in each list type, the list types you can create instances of through the Create Page used to create lists, or the lists included in a particular configuration within a site definition.
  • FLDTYPES.XML defines how the different data types used in Windows SharePoint Services are conveyed or represented through list item forms.

Each list type, however, also draws much of its definition from the contents of a folder within the Local_Drive:\Program Files\Common Files\Microsoft Shared\web server extensions\60\TEMPLATE\Locale_ID\Site_Definition\LISTSdirectory, exclusively devoted to the particular list type. For most list types the folder contains at least five files:

  • AllItems.aspx for viewing all the items in a list

  • NewForm.aspx for creating list items

  • DisplayForm.aspx for displaying list items

  • EditForm.aspx for editing list items

  • SCHEMA.XML defines special fields for the list, as well as list views, the Related Tasks toolbar, and main contents of views used in list item forms

    Note   For general information about site and list definitions, see Introduction to Templates and Definitions.

All three XML files mentioned previously use Collaborative Application Markup Language (CAML) to define how list instances are created. CAML is used to define and declare fields that compose a list and become represented in a form. In addition, drawing on site or list metadata available at the time, Windows SharePoint Services uses CAML to conditionally construct the appropriate user interface for the form.

Warning   Do not modify the contents of FLDTYPES.XML because doing so can break all site definitions on a front-end Web server. Also, as described later in this article, create a custom site definition by copying an existing site definition, rather than modifying the original files installed with Windows SharePoint Services. Changes you make to originally installed files may be overwritten when you install updates or service packs for Windows SharePoint Services, or when you upgrade an installation to the next product version. For information on creating a custom site definition, see Creating a Site Definition from an Existing Definition.

List Item Form Page Layout

The three ASPX pages providing the list item forms are very similar, containing the same page directives, metadata, script, and Windows SharePoint Services Web server controls. In addition, each ASPX page contains a table consisting of three rows: one for the banner or top navigation area, another for the title area, and a third for both the left navigation and content areas.

Figure 1. Table in an ASPX page

The four cells represented in the table in Figure 1 indicate areas that you can customize or remove entirely from the page.

You can add other Web Part zones to the page declaratively in the same way by adding a Web Part zone with a unique ID. When you embed a custom Web Part within a list item form definition in SCHEMA.XML, the value of the WebPartZoneID attribute on the AllUsersWebPart element containing the part corresponds to the value of the ID attribute of the WebPartZone control.

The FrameType attribute of a Web Part zone describes the border used for the Web Part. You set it to one of the following values:

  • None: Use no frame or title bar.
  • Standard: Use frame and title bar.
  • TitleBarOnly: Use title bar but no frame.

The zone specifies where to insert a Web Part into the page, and the Web Part in turn conveys the item view that is defined in the forms section of the SCHEMA.XML file for the particular list type.

Form View Definition

Two sections in the SCHEMA.XML file for a list type are important for the purposes of customizing forms: the opening Fields element that defines special fields for the list, and the Forms element that contains the form view for each form type.

Fields Section

The fields section at the beginning of the SCHEMA.XML file for a particular list type contains descriptions of any special fields that you must implement in a list instance. A tasks list schema, for example, unlike other list types, has the following fields section, which includes two choice fields and several other field types, some with specified default values.

<Fields>
  <Field Type="Choice" Name="Priority" DisplayName="Priority">
    <CHOICES>
      <CHOICE>(1) High</CHOICE>
      <CHOICE>(2) Normal</CHOICE>
      <CHOICE>(3) Low</CHOICE>
    </CHOICES>
    <Default>(2) Normal</Default>
  </Field>
  <Field Type="Choice" Name="Status" DisplayName="Status">
    <CHOICES>
      <CHOICE>Not Started</CHOICE>
      <CHOICE>In Progress</CHOICE>
      <CHOICE>Completed</CHOICE>
      <CHOICE>Deferred</CHOICE>
      <CHOICE>Waiting on someone else</CHOICE>
    </CHOICES>
    <Default>Not Started</Default>
  </Field>
  <Field Type="Number" Name="PercentComplete" Percentage="TRUE" Min="0" 
  Max="1" DisplayName="% Complete"></Field>
  <Field Type="User" List="UserInfo" Name="AssignedTo" 
  DisplayName="Assigned To"></Field>
  <Field Type="Note" RichText="TRUE" Name="Body" 
  DisplayName="Description" Sortable="FALSE"></Field>
  <Field Type="DateTime" Name="StartDate" DisplayName="Start Date">
    <Default>[today]</Default>
  </Field>
  <Field Type="DateTime" Name="DueDate" DisplayName="Due Date">
  </Field>
</Fields>

In addition to the Title field, which is defined by default for all list types, each field specified within the preceding Fields element is displayed in the list item form in the order listed.

Users can easily add a column to an existing list through the user interface, but by adding a field to the opening enumeration of fields in SCHEMA.XML, you make the field available generally to the particular list type, so that future lists created through the list definition include the column by default. For a programming task that steps through the process of adding a field to a list definition, see Adding a Field to a List Definition.

The field order in the Fields section determines the order in which fields are represented in the user interface of a form. To change the order of fields in the form, change their order within the opening Fields element.

Note   If end users have already created list instances using the list definition and modified their fields, for example, by adding a new field or changing the display name of an existing field, changing the field order in SCHEMA.XML has no effect.

Forms Section

The Forms element in SCHEMA.XML contains the view and defines the content for each type of form, which includes the list item toolbar and all content appearing beneath the toolbar within the page body. A Web Part inserts an HTML <DIV> tag and two nested <Table> tags in the page, while SCHEMA.XML defines all the content that is conveyed through the Web Part.

The Form element contains the form view for a specified type, as follows.

<Form Type="EditForm" Url="EditForm.aspx" WebPartZoneID="Main">

You must set the Type attribute to DisplayForm, EditForm, or NewForm. The Url attribute identifies the page that displays the list item form, and you can use this attribute to specify an alternate page to use as the form for a given type. The WebPartZoneId attribute identifies the form view with the ID of a particular Web Part zone, as described earlier.

A Form element for one of the types can contain the following optional subelements:

  • ListFormOpening constructs the form, hidden input posted through the form, and also script blocks containing methods to respond to UI events.
  • ListFormButtons defines the list item toolbar and the commands it contains.
  • ListFormBody constructs the script that is inserted in the page in order to build the controls for displaying or typing values for each field. Also creates all information appearing at the bottom of the form beneath the item.
  • ListFormClosing used in New and Edit item forms to define the alternate UI that appears when the user clicks Attach File on the toolbar.
  • WebParts contains declarations of any Web Parts included in the list item form. This element contains either a View element or AllUsersWebPart element. Use the View element for Web Parts that convey list views, where the view conveyed through the part is defined in a CAML schema; use the AllUsersWebPart for all other kinds of Web Parts.

The main purpose of these subelements is to serve as convenient separators between sections in the form definition to assist in page design. You can modify their contents individually, remove them entirely, or merge them together within a single element. In fact, the Form element can contain the entire form definition directly without mediation through any of these elements.

Note   To help ensure that forms you customize will work well in future versions of Windows SharePoint Services, you should use Microsoft ASP.NET controls to customize forms. Modifying the contents of Form elements in SCHEMA.XML might not carry over if the form infrastructure changes in future versions of Windows SharePoint Services.

Creating a Custom Site Definition

Follow this important guideline when you customize site or list definitions: Work from copies of native SharePoint files, and do not modify the original files. Create a custom site definition from an originally installed site definition, for example, the standard STS definition or the MPS definition for Meetings.

Note   To review a programming task that steps through the process of creating a custom site definition, see Creating a Site Definition from an Existing Site Definition.

Working from a copy of a site definition helps ensure code reusability and protects your customizations when patches or upgrades are applied to the deployment.

The following sections describe tasks you can perform to customize a site definition. Before you start the following tasks, however, create a custom site definition and try out the examples in the following sections only in the copied files of your definition.

Adding Left Navigation to a Form Through Web Server Controls

The left navigational area in list item forms is blank by default, but you can add links to use this area. As shown in Figure 1, the table style ms-navframe indicates this area, which appears as follows in the ASPX page.

    <!-- Navigation -->
<TR> 
<TD valign=top height=100% class=ms-nav> <TABLE height=100% 
class=ms-navframe CELLPADDING=0 CELLSPACING=0 border="0" width=126px> 
<tr> <td valign=top width=100%>&nbsp;</td> <td valign=top 
class=ms-verticaldots>&nbsp;</td> </tr> </TABLE> </TD>
    <!-- Contents -->

We will demonstrate three ways to add left navigation to the DispForm.aspx file of a tasks list. Each method contributes to a consistent user interface and to easier link maintenance because its code is centralized and you can modify it from a single location. You can add left navigation by:

  • Inserting the ViewSelector control in the page to offer users a choice between task list views.
  • Inserting Navigation controls to display particular Quick Launch links.
  • Inserting a custom Web server control that returns and displays items from a centralized SharePoint links list.

The following example involves modifying the DispForm.aspx file of a custom tasks list definition and creating a Web server control in Microsoft Visual Studio .NET that uses the Microsoft.SharePoint namespace to return links list items, and the System.Web.UI.WebControls namespace to build the user interface for displaying them. Figure 2 shows the left navigational area, which offers users immediate access to important resources that may be related to the task.

Figure 2. Left navigational area of a tasks list

  1. Open the DispForm.aspx page of the tasks list definition at Local_Drive:\Program Files\Common Files\Microsoft Shared\web server extensions\60\TEMPLATE\Locale_ID\Custom_Site_Definition\LISTS\TASKS, and locate the ms-navframe table shown earlier. This example replaces the first nonbreaking space in this section with three rows containing three tables that contribute different parts of the left navigational area.

  2. Replace the first nonbreaking space in the preceding ms-navframe table with a table such as the following, which inserts a View Selector within the cell containing the nonbreaking space.

    <TABLE style="margin-left: 3px" width=115px>
    <TR><TD>Select a View</TD></TR>
    <TR><TD class="ms-navline">
    <IMG SRC="/_layouts/images/blank.gif"></TD></TR>
    <TR><TD><SharePoint:ViewSelector /></TD></TR>
    </TABLE>
    </td></tr>
    
  3. Add code like the following after the previous row, which inserts a table containing the Quick Launch links that appear under the Documents and Discussions headings displayed on the home page:

    <tr><td>
    <TABLE style="margin-left: 3px" width=115px>
    <TR><TD>Resources</TD></TR>
    <TR><TD class="ms-navline">
    <IMG SRC="/_layouts/images/blank.gif"></TD></TR>
    <TR><TD style="padding-left:10px">
    <SharePoint:Navigation LinkBarId="1004" /></TD></TR>
    <TR><TD style="padding-left:10px">
    <SharePoint:Navigation LinkBarId="1006" /></TD></TR>
    </TABLE>
    
  4. Reset Microsoft Internet Information Services (IIS) so that changes you made can take effect.

To create and implement a Web server control

  1. Create a links list called OrgList that you can use to maintain the list of links that the Web server control will display. Add items to the new list.

  2. In Microsoft Visual Studio .NET, create a Web Control Library project by pointing to New, and on the File menu, clicking Project. In this example the project is named ServerControl1.

  3. To set the build output path to the wwwroot/bin directory, right-click the project name in Solution Explorer, click Properties. In the Property Pages dialog box under Configuration Properties, click Build to set the value of Output Path to Local_Drive:\Inetpub\wwwroot\bin. The DLL of the project you create must reside in this directory for the control to work.

  4. Add a reference to the Windows SharePoint Services assembly. To do this, right-click References in Solution Explorer, click Add Reference, and on the .NET tab, click Windows SharePoint Services. Click OK.

  5. To import namespaces not already included by default in the project, add the following directives near the beginning of the .cs file in the project.

    using Microsoft.SharePoint;
    using Microsoft.SharePoint.WebControls;
    using System.Web.UI.HtmlControls;
    
  6. To return SharePoint list data and build controls to display it, override the Control.CreateChildControls method.

    protected override void CreateChildControls ()
    { 
      string strLitCtrl1 = "<TABLE style=\"margin-left: 3px\"" + 
          " width=115px cellpadding=0 cellspacing=2 BORDER=0>" + 
          "<TR><TD width=100%>Organization</TD></TR>" + 
          "<TR><TD class=\"ms-navline\">" + 
          "<IMG SRC=\"/_layouts/images/blank.gif\" width=1 " + 
          "height=1 alt=\"\"></TD></TR> </TABLE><TABLE>";
      LiteralControl tblStart = new LiteralControl(strLitCtrl1);
      Controls.Add(tblStart);
    
      SPSite siteColl = SPControl.GetContextSite(Context);
      SPList list = siteColl.RootWeb.Lists["OrgLinks"];
      SPListItemCollection items = list.Items;
    
      foreach (SPListItem item in items)
      {
        string strStart = "<TR><TD width=9px>" + 
            "<IMG SRC=\"/_layouts/images/blank.gif\" " + 
            "width=1 height=1 alt=\"\"></TD>" + 
            "<TD style=\"padding-bottom: 6px\">";
        LiteralControl rowStart = new LiteralControl(strStart);
        Controls.Add(rowStart);
    
        string myString = item["URL"].ToString();
        int indexComma = myString.IndexOf(",");
        string strUrl = myString.Substring(0,indexComma);
        string strTitle = myString.Substring(indexComma + 2);
    
        HtmlAnchor orgLink = new HtmlAnchor();
        orgLink.HRef = strUrl;
        orgLink.Title = strTitle;
        orgLink.Target = "_self";
        orgLink.InnerText = strTitle;
        Controls.Add(orgLink);
    
        string strEnd = "</TD></TR>";
        LiteralControl rowEnd = new LiteralControl(strEnd);
        Controls.Add(rowEnd);
      }
    
      LiteralControl tblEnd = new LiteralControl("</TABLE>");
      Controls.Add(tblEnd);
    }
    

    The previous procedure starts by using a LiteralControl control to create the unrepeatable opening section of the table, and then iterates through all the list items and adds a row for each item returned. Because the item["URL"] indexer returns both the URL and the inner text (the link text) in the form URL, Inner_Text, the example parses out the two strings using the String.Substring method, and then assigns them to the Href and Title properties of an HtmlAnchor control.

  7. Use the Control.RenderChildren method within the Control.Render method override, as follows.

    RenderChildren(output);
    
  8. To build the Web server control, on the Build menu, click Build Solution, or press CTRL+SHIFT+B.

  9. To use the control, you must register it as a safe control in Windows SharePoint Services by using sn.exe to create a key pair, and registering the control in the /wwwroot/web.config file. For information on this process, which is the same one used to register Web Parts, see "Register your Web Part as a SafeControl" in Creating a Basic Web Part.

  10. Add a directive at the top of DispForm.aspx to register the custom server control, as follows, replacing the PublicKeyToken value used in the example with the actual PublicKeyToken value of your control.

    <%@ Register Tagprefix="OrgLinks" Namespace="ServerControl1" 
    Assembly="ServerControl1, Version=1.0.0.0, Culture=neutral, 
    PublicKeyToken=73af0f2b510c7894" %>
    
  11. After the row added in step 3 of the procedure Inserting a View Selector and QuickLaunch links (see Adding Left Navigation to a Form Through Web Server Controls), add the server control declaratively as follows.

    <TR><TD><OrgLinks:WebCustomControl1 />
    
  12. For your changes to take effect, reset IIS.

You can insert the custom Web server control on numerous pages in a deployment, but the URLs that it displays can be managed from a single location—the list called OrgList that you created previously.

Embedding a Web Part in a Form and in the Home Page to Display List Data

In SharePoint Team Services from Microsoft, the previous version of Microsoft Windows SharePoint Services, you could embed a CAML list view within an XML data island (indicated by <ows:XML>) directly in the HTML page. For examples of this procedure, see Custom CAML Views in SharePoint Team Services. Custom views as described in this article were static, meaning you needed to embed their code in the source of the home page. In Windows SharePoint Services, list views are conveyed through Web Parts, using types and members of the Microsoft.SharePoint namespace to access list data, and ASP.NET controls to build the user interface. Web Parts are inherently dynamic, and unlike the previous custom CAML views, their code does not need to be contained within the source.

This example steps through the process of creating a Web Part that displays overdue tasks belonging to the current user, and embedding the part in the display form for task items and in the home page. Figure 3 shows the Web Part in the display form, which lists the current user's overdue tasks, if any.

Figure 3. Overdue tasks Web Part

Warning   Adding a list view Web Part (ListViewWebPart class) to a list item form or default.aspx file in Windows SharePoint Services might cause adverse effects in the behavior of the page. Adding more than one list-related Web Part to a page, such as the one used in this example, is not supported.

To create a custom list view and add it to a form

  1. Create a Web Part as described in Creating a Basic Web Part, replacing SimpleWebPart with OverdueTasksPart in the procedure globally. To briefly summarize, the process of creating a Web Part entails the following steps:

    1. In Visual Studio .NET, create a Web Part application.
    2. Set the build path of the project to C:\inetpub\wwwroot\bin.
    3. Using sn.exe, give the assembly a strong name, and then modify AssemblyInfo.cs accordingly.
    4. In the Web Part's WebPart1.cs file, add the code to execute.
    5. In the \wwwroot web.config file, register the Web Part as a safe control.
    6. Modify the project's .dwp file.
  2. At the top of the .cs file, add directives to import the required namespaces.

    using System;
    using System.Text.RegularExpressions;
    using System.ComponentModel;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.Xml.Serialization;
    using Microsoft.SharePoint;
    using Microsoft.SharePoint.Utilities;
    using Microsoft.SharePoint.WebControls;
    using Microsoft.SharePoint.WebPartPages;
    
  3. Replace the SimpleWebPart example code within the Control.CreateChildControls method with the following code, which begins the construction of a table for viewing list data.

    Label lblTable = new Label();
    lblTable.Font.Name = "Verbena";
    lblTable.Text = "Your Overdue Tasks";
    lblTable.Font.Size = FontUnit.Larger;
    lblTable.Font.Bold = true;
    lblTable.ForeColor = System.Drawing.Color.Red;
    this.Controls.Add(lblTable);
    
    Table tbl = new Table();
    tbl.BorderWidth = 1;
    this.Controls.Add(tbl);
    
    TableRow rowHeader = new TableRow();
    rowHeader.Font.Size = FontUnit.Parse(".68em");
    rowHeader.Font.Bold = true;
    rowHeader.BackColor = System.Drawing.Color.LightGray;
    rowHeader.ForeColor =  
    System.Drawing.ColorTranslator.FromHtml("#003399");
    
    TableCell cellHeader1 = new TableCell();
    cellHeader1.Text = "Title";
    rowHeader.Cells.Add(cellHeader1);
    
    TableCell cellHeader2 = new TableCell();
    cellHeader2.Text = "Priority";
    rowHeader.Cells.Add(cellHeader2);
    
    TableCell cellHeader3 = new TableCell();
    cellHeader3.Text = "Due Date";
    rowHeader.Cells.Add(cellHeader3);
    
    tbl.Rows.Add(rowHeader);
    
  4. Immediately after the code added in step 2, add code that iterates through all task lists of the current site to return and display any overdue items belonging to the current user.

    SPWeb currentSite = SPControl.GetContextWeb(Context);
    int wpVisible = 0;
    SPListCollection lists = currentSite.Lists;
    
    foreach (SPList list in lists)
    {
       if (list.ItemCount > 0 && 
          list.BaseTemplate == SPListTemplateType.Tasks)
       {
          SPQuery query = new SPQuery();
          query.Query = "<Where><Eq><FieldRef Name = \"AssignedTo\"/>" + 
             "<Value Type=\"Integer\"><UserID/></Value></Eq></Where>";
    
          SPListItemCollection listItems = list.GetItems(query);
    
          foreach (SPListItem item in listItems)
          {
             if (item["Due Date"] != null && 
                 item["Assigned To"] != null && 
                 item["Status"].ToString() != "Completed")
             {
                if (Convert.ToDateTime(item["Due Date"]) <= 
                     System.DateTime.Now)
                {
                   TableRow row = new TableRow();
                   string frmUrl = userSite.Url + "/" + 
                   list.Forms[PAGETYPE.PAGE_DISPLAYFORM].Url.ToString();
                   string strUrl = "<a href=\"" + frmUrl +  
                   "?ID=" + item.ID.ToString() + "\">" + 
                   item["Title"].ToString() + "</a>";
    
                   TableCell cell1 = new TableCell();
                   cell1.Text = strUrl;
                   cell1.BorderWidth = 1;
                   row.Cells.Add(cell1);
    
                   TableCell cell2 = new TableCell();
                   cell2.Text = item["Priority"].ToString();
                   cell2.BorderWidth = 1;
                   row.Cells.Add(cell2);
    
                   TableCell cell3 = new TableCell();
    
                   if (item["Due Date"]!= null)
                   {
                      cell3.Text = item["Due Date"].ToString();
                   }
                   else
                   {
                      cell3.Text = "";
                   }
    
                   cell3.BorderWidth = 1;
                   row.Cells.Add(cell3);
                   tbl.Rows.Add(row);
    
                   wpVisible = 1;
                }
             }
          }
       }
    }
    
    if (wpVisible == 0)
    {
       this.Visible = false;
    }
    

    The example uses the GetItems(Microsoft.SharePoint.SPQuery) method to return survey responses for the current user, constructing and assigning a CAML string to the Query property of an SPQuery object, which is then passed as the parameter of the GetItems method.

    The example uses a wpVisible flag to determine whether the Web Part is visible. If the user has any overdue items, the flag is set to 1 and the Web Part is visible.

  5. Replace the code in the RenderWebPart method with the following code to render the controls added in the example.

    EnsureChildControls();
    RenderChildren(output);
    
  6. To build the Web Part, on the Build menu, click Build Solution, or press CTRL+SHIFT+B.

  7. Register the Web Part as a safe control in Windows SharePoint Services (for details, see "Register your Web Part as a SafeControl" in Creating a Basic Web Part).

  8. In Notepad or another text editor, open SCHEMA.XML at Local_Drive:\Program Files\Common Files\Microsoft Shared\web server extensions\60\TEMPLATE\Locale_ID\Custom_Site_Definition\LISTS\TASKS and find the Form element for the display item form, which starts with <Form Type="DisplayForm" Url="DispForm.aspx" WebPartZoneID="Main">.

  9. Add the following code immediately before the closing <Form> tag of the display item form, replacing the PublicKeyToken value used in the example with the actual PublicKeyToken value of your Web Part.

    <WebParts>    
      <AllUsersWebPart WebPartZoneID="Main" WebPartOrder="2">
        <![CDATA[ 
          <WebPart xmlns="http://schemas.microsoft.com/WebPart/v2"> 
          <Assembly> OverdueTasksPart, Version=1.0.0.0, Culture=neutral,
           PublicKeyToken=33c030758c3fa08e</Assembly> 
          <TypeName>OverdueTasksPart.WebPart1</TypeName> 
          <Title>Your Overdue Tasks</Title> 
          <Description></Description> 
          <FrameType>None</FrameType>
          </WebPart>]]> 
      </AllUsersWebPart>
    </WebParts>
    

    The FrameType value is set to None so that the standard Web Part frame and title bar are not displayed. This Web Part is displayed second in order within the Web Part zone with the ID of Main, although you could add another Web Part zone to the ASPX page and the Web Part could then be identified with the new zone.

  10. Save your changes to SCHEMA.XML, and then reset IIS. You may also need to create a new list through the list definition for the changes to take effect.

To add the custom view to the home page

  1. To embed the overdue tasks view in the home page, open the ONET.XML file at C:\Program Files\Common Files\Microsoft Shared\web server extensions\60\TEMPLATE\Locale_ID\Custom_Site_Definition\XML and find the first Module element (Name="Default") in the collection of Module elements located at the end of the file.

  2. After the following View element:

    <View List="103" BaseViewID="0" WebPartZoneID="Right" 
    WebPartOrder="2"/>
    

    Place an AllUsersWebPart element, such as the one added in the previous step, but replace the PublicKeyToken value used in the example with the actual PublicKeyToken value of your Web Part.

    <AllUsersWebPart WebPartZoneID="Left" WebPartOrder="3">
       <![CDATA[
          <WebPart xmlns="http://schemas.microsoft.com/WebPart/v2">
             <Assembly>WPContainer1, Version=1.0.0.0, Culture=neutral,
              PublicKeyToken=33c030758c3fa08e</Assembly>
             <TypeName>OverdueTasksPart.WebPart1</TypeName>
             <FrameType>None</FrameType>
             <Title>Your Overdue Tasks</Title>
          </WebPart>]]>
    </AllUsersWebPart>
    
  3. Save your changes to ONET.XML, and then reset IIS.

Creating a Form to Extend the Reach of a Survey

As we saw in the previous example, you can add a list view to a list item form. In addition, you can add a list item form to a Web Part zone in the AllItems.aspx page for viewing a list, or in the home page. Web Parts provide a means for extending the reach of list item forms to various locations in a site. By using Web Parts and the Microsoft .NET Framework to construct a form, you have an alternative to using CAML schema customizations, as discussed in Advanced Customizations.

The following example shows how to make a list item form for a survey that appears on the home page if the current user hasn't already taken the survey. The form includes validation for the fields, and when the user clicks Submit, a message appears with a button for closing the form. Figure 4 shows the Web Part as displayed on the home page.

Figure 4. Web Part conveying a survey form

To create a Web Part for extending a survey

  1. To run the following example, create a simple survey called TestSurvey in the top-level site of the site collection in which you want to deploy the form. Use the following four questions for the survey, using the indicated column types.

    • Is your group interested in attending the conference? (Yes/No (check box))
    • City (single line of text)
    • Level (choice (menu to choose from))
    • Zip Code (single line of text)
  2. Create a Web Part as described in Creating a Basic Web Part, replacing SimpleWebPart with TestSurvey in the procedure globally.

  3. At the top of the .cs file, add directives to import the required namespaces as follows.

    using System;
    using System.ComponentModel;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.Xml.Serialization;
    using Microsoft.SharePoint;
    using Microsoft.SharePoint.Utilities;
    using Microsoft.SharePoint.WebControls;
    using Microsoft.SharePoint.WebPartPages;
    using System.Web.UI.HtmlControls;
    
  4. Declare variables to use within the class of the .cs file.

    private SPSite siteCollection;
    private SPList list;
    private SPListItemCollection items;
    
    private RadioButton radio1;
    private RadioButton radio2;
    private HtmlInputText textbox1;
    private HtmlInputText textbox2;
    private DropDownList dropdown1;
    private HtmlButton button1;
    private Label label5;
    private HtmlAnchor closepart;
    
  5. Define a button1_click event for the Submit button, which gathers the data the user entered and adds a new item to the list. The procedure also changes the visibility of a label for displaying a message and of a button to close the Web Part to true.

    SPListItem item = items.Add();
    
    if (radio1.Checked == true)
    {
       item["Is your group interested in attending the conference?"] 
       = "1";
    }
    else
    {
       item["Is your group interested in attending the conference?"] 
       = "0";
    }
    
    item["City"] = textbox1.Value;
    item["Level"] = dropdown1.SelectedItem.Value;
    item["Zip_x0020_ Code"] = textbox2.Value;
    item.Update();
    
    label5.Text = "Thanks for taking the survey!";
    label5.Visible = true;
    
    closepart.Visible = true;
    
    siteCollection.Close();
    
  6. Define a closepart_click event for the button to close the form.

    public void closepart_click (object sender, EventArgs e)
    {
       this.Visible = false;
    }
    
  7. Use the Control.CreateChildControls method override to build the user interface programmatically, first checking if the current user has already taken the survey and, if so, hiding the form and exiting the procedure.

    siteCollection = SPControl.GetContextSite(Context);
    list = siteCollection.RootWeb.Lists["TestSurvey"];
    
    SPQuery query = new SPQuery();
    query.Query = "<Where><Eq><FieldRef Name = \"Author\"/>" + 
       "<Value Type=\"Integer\"><UserID/></Value></Eq></Where>";
    
    items = list.GetItems(query);
    
    if (items.Count > 0)
    {
       this.Visible = false;
       return;
    }
    

    The example uses the GetItems(Microsoft.SharePoint.SPQuery) method to return survey responses for the current user, constructing a CAML string and assigning it to the Query property of an SPQuery object, which is then passed as the parameter of the GetItems method.

  8. If the user has not already taken the survey, the example proceeds to construct the user interface using .NET Framework controls. You can group option buttons by using the RadioButton.GroupName property, as follows.

    Controls.Add(new LiteralControl("<BR>"));
    Label label1 = new Label();
    label1.Text = "Is your group interested in attending 
        the conference? ";
    Controls.Add(label1);
    
    Controls.Add(new LiteralControl("<BR><BR>"));
    radio1 = new RadioButton();
    radio1.Text = "Yes";
    radio1.Checked = true;
    radio1.GroupName = "interest";
    Controls.Add(radio1);
    
    radio2 = new RadioButton();
    radio2.Text = "No";
    radio2.GroupName = "interest";
    Controls.Add(radio2);
    

    Use a RequiredFieldValidator control to verify that values are specified for required fields.

    Controls.Add(new LiteralControl("<BR><BR>"));
    Label label2 = new Label();
    label2.Text = "City   ";
    Controls.Add(label2);
    
    textbox1 = new HtmlInputText();
    textbox1.Value="";
    textbox1.ID = "ctlWhere";
    Controls.Add(textbox1);
    
    RequiredFieldValidator rfValid1 = new RequiredFieldValidator();
    rfValid1.ControlToValidate = "ctlWhere";
    rfValid1.ErrorMessage = "Please specify the name of a city.";
    rfValid1.Display = System.Web.UI.WebControls.ValidatorDisplay.Static;
    Controls.Add(rfValid1);
    

    To apply the RequiredFieldValidator control to a drop-down list box, use the InitialValue property to determine whether the user made a selection, as follows.

    Controls.Add(new LiteralControl("<BR><BR>"));
    Label label3 = new Label();
    label3.Text = "Level   ";
    Controls.Add(label3);
    
    dropdown1 = new DropDownList();
    dropdown1.ID = "ctlLevel";
    dropdown1.Items.Add(new ListItem("Select Level","Select Level"));
    dropdown1.Items.Add(new ListItem("One","One"));
    dropdown1.Items.Add(new ListItem("Two","Two"));
    dropdown1.Items.Add(new ListItem("Three","Three"));
    Controls.Add(dropdown1);
    
    RequiredFieldValidator rfValid2 = new RequiredFieldValidator();
    rfValid2.ControlToValidate = "ctlLevel";
    rfValid2.ErrorMessage = "Please specify a level.";
    rfValid2.InitialValue = "Select Level";
    rfValid2.Display = System.Web.UI.WebControls.ValidatorDisplay.Static;
    Controls.Add(rfValid2);
    

    Use the RegularExpressionValidator control to make sure the user types values in special fields in the expected format, such as the following example, which verifies values entered for the zip code box that is created.

    Controls.Add(new LiteralControl("<BR><BR>"));
    Label label4 = new Label();
    label4.Text = "Zip Code   ";
    Controls.Add(label4);
    
    textbox2 = new HtmlInputText();
    textbox2.Value="";
    textbox2.ID = "ctlZip";
    Controls.Add(textbox2);
    
    RequiredFieldValidator rfValid3 = new RequiredFieldValidator();
    rfValid3.ControlToValidate = "ctlZip";
    rfValid3.ErrorMessage = "Please specify a zip code.";
    rfValid3.Display = System.Web.UI.WebControls.ValidatorDisplay.Static;
    Controls.Add(rfValid3);
    
    RegularExpressionValidator regex = new RegularExpressionValidator();
    regex.ControlToValidate = "ctlZip";
    regex.ValidationExpression = "[0-9]{5}(-[0-9]{4})?";
    regex.Text = "Please enter a valid zip code.";
    regex.Display = System.Web.UI.WebControls.ValidatorDisplay.Static;
    Controls.Add(regex);
    

    Use the HtmlAnchor.ServerClick event to associate a button click with a specific event handler:

    Controls.Add(new LiteralControl("<BR><BR>"));
    button1 = new HtmlButton();
    button1.InnerText = "Submit";
    button1.ServerClick += new EventHandler (button1_click);
    Controls.Add (button1);
    

    To prevent a control from being visible initially, set its Visible property to false when creating the control.

    Controls.Add(new LiteralControl("<BR><BR>"));
    label5 = new Label();
    label5.Visible = false;
    Controls.Add(label5);
    
    Controls.Add(new LiteralControl("<BR><BR>"));
    closepart = new HtmlAnchor();
    closepart.InnerText = "Close";
    closepart.ServerClick += new EventHandler (closepart_click);
    closepart.Visible = false;
    Controls.Add (closepart);
    
    siteCollection.Close();
    
  9. The RenderWebPart method renders the controls on the page.

    RenderChildren(output);
    
  10. To build the Web Part, on the Build menu, click Build Solution, or press CTRL+SHIFT+B.

  11. Register the Web Part as a safe control in Windows SharePoint Services (for details, see "Register your Web Part as a SafeControl" in Creating a Basic Web Part).

  12. To import the Web Part into a home page, click Modify Shared Page on the home page, point to Add Web Part, click Import, browse to the .dwp file of the Web Part, and click Upload. Drag the part into a zone.

    Note   This example assumes the existence of a survey list like the one represented in Figure 4 that is located in the top-level site of the site collection.

Advanced Customizations

The following sections describe advanced customizations that might not carry over into future versions of Windows SharePoint Services if the form infrastructure changes. The tasks involve customizing Form elements in SCHEMA.XML, rather than using ASP.NET controls, to customize forms.

Modifying the Toolbar and Body in a Form

This task involves adding code to the SCHEMA.XML file of the Tasks list definition that adds a different link to the toolbar and different additional text in the body depending on certain conditions. If the item has an attachment, a different link is added to the toolbar depending on the priority of the task. A link does not appear if the priority is low or if there is no attachment. Figure 5 shows the text that is displayed to draw the user's attention to the additional link on the toolbar.

Figure 5. Custom text and link displayed in a form

To modify the toolbar and body in a form

  1. In Notepad or another text editor, open the SCHEMA.XML file of the Tasks list in your custom site definition at Local_Drive:\Program Files\Common Files\Microsoft Shared\web server extensions\60\TEMPLATE\Locale_ID\Custom_Site_Definition\LISTS\TASKS.

  2. To add a link at the end of the toolbar, find the ListFormButtons element in the form definition for the DisplayForm type and locate the following table cell near the end of this section, which defines the Go Back to List link.

    <TD class="2ms-toolbar">
        <table cellpadding=1 cellspacing=0 border=0>
        <tr><td colspan=2 nowrap>
            <a tabindex=2 class="ms-toolbar" ACCESSKEY=G ID=diidIOGoBack
            href="]]></HTML>
    <ListProperty Select='DefaultViewUrl'/>
    <HTML><![CDATA[" onclick="javascript:GoBack(']]></HTML>
    <ScriptQuote NotAddingQuote="TRUE">
    <ListProperty Select="DefaultViewUrl"/></ScriptQuote>
    <HTML><![CDATA[');return false;" target="_self">
    <LocID ID="L_GOBackItem">]]></HTML>
    <HTML>Go Back to List</HTML>
    <HTML><![CDATA[</LocID>
            </a></td></tr></table>
    </TD>
    

    The example shows how CAML is frequently used to prepare HTML for the browser, where certain elements are used to intersperse item, list, and project property values within the markup language sections contained in HTML elements. In this example, we use the ListProperty element to return the URL of the default view for the list.

    Good resources for discovering possible values that you can assign to the Select attribute of ListProperty include the natively installed CAML files, as well as attributes listed for the List element, and numerous properties of the SPList class. You can use the ProjectProperty element, Property element, and ServerProperty element to return site-scoped or server-scoped Windows SharePoint Services property values.

  3. Add the following code example immediately after the last closing table cell tag (</TD>) shown in the code example of step 2 for the Go Back to List button, which adds an additional cell if the item has an attachment and the Priority field contains High or Medium.

    <!--Add the following code-->
     ]]></HTML>
    <Switch>
      <Expr><Field Name="Attachments"/></Expr>
      <Case Value=""/>
      <Default>
        <Switch>
          <Expr><Field Name="Priority"/></Expr>
          <Case Value="(1) High">
            <HTML><![CDATA[
              <TD class=ms-separator>|</td>
              <TD class="2ms-toolbar">
              <table cellpadding=1 cellspacing=0 border=0>
              <tr><td colspan=2 nowrap>
              <a tabindex=2 class="ms-toolbar" href="FirstUrl">High 
              Priority Resolution Guidelines   
              </a><br></td></tr></table></TD>]]>
            </HTML>
          </Case>
          <Case Value="(2) Normal">
            <HTML><![CDATA[
              <TD class=ms-separator>|</td>
              <TD class="2ms-toolbar">
              <table cellpadding=1 cellspacing=0 border=0>
              <tr><td colspan=2 nowrap>
              <a tabindex=2 class="ms-toolbar" href="SecondUrl">  
              Guidelines</a>
              </td></tr></table></TD>]]>
            </HTML>
          </Case>
          <Default></Default>
        </Switch>
      </Default>
    </Switch>
    <HTML><![CDATA[
    

    The example interposes nested Switch element statements within the page definition, evaluating first the Attachments field and then the Priority field to create the appropriate HTML. If the Attachments field evaluates to an empty string, then no action is taken. If there is an attachment, a different URL is provided in the toolbar depending on the priority. The default is to add no URL to the toolbar when the priority is low.

    For a list of the fields available by default for a given list type that can be evaluated for an item, as shown in the example, see Field Tables for Default Lists.

    Note   Replace the placeholders used as URLs in the example with actual links.

  4. Find the following block of code near the end of the ListFormBody element, which creates the section line that appears at the bottom of the item form.

    <HTML><![CDATA[
    <table border=0 cellpadding=0 cellspacing=0 width=100%>
     <tr><td>&nbsp;</td></tr>
     <tr><td class="ms-formlabel"> 
       <table border=0 cellpadding=0 cellspacing=4 width=100%>
        <tr><td class="ms-sectionline" height=1>
    
  5. Replace the nonbreaking space (&nbsp;) in the previous cell with the following example, which uses the same nested Switch statements, as in step 3, to conditionally add text to the form body.

    ]]></HTML>
    <Switch>
      <Expr><Field Name="Attachments"/></Expr>
      <Case Value=""/>
      <Default>
        <Switch>
          <Expr><Field Name="Priority"/></Expr>
          <Case Value="(1) High">
            <HTML><![CDATA[
              <table border=0 cellpadding=0 cellspacing=0>
              <tr><td class="ms-formbody">
              Click the High Priority Resolution Guidelines link on
              the toolbar for directions  about completing this 
              task.</td></tr><tr><td>
              <img border=0 width=1 height=3 
              src="/_layouts/images/blank.gif" alt="">
              </td></tr></table>]]></HTML>
          </Case>
          <Case Value="(2) Normal">
            <HTML><![CDATA[
              <table border=0 cellpadding=0 cellspacing=0>
              <tr><td class="ms-formbody">
              Click the Guidelines link on the toolbar for 
              directions about completing this task.  
              </td></tr><tr><td>
               <img border=0 width=1 height=3 
               src="/_layouts/images/blank.gif" alt="">
               </td></tr></table>]]></HTML>
          </Case>
          <Default>
            <HTML><![CDATA[
              <table border=0 cellpadding=0 cellspacing=0>
              <tr><td class="ms-formbody">
              You might find the attached file useful in preparing 
              for this task, but its use is  optional.
              </td></tr><tr><td>
              <img border=0 width=1 height=3 
              src="/_layouts/images/blank.gif" alt="">
              </td></tr></table>]]></HTML>
          </Default>
        </Switch>
      </Default>
    </Switch>
    <HTML><![CDATA[
    

    If the priority is high or normal, the example adds different text that draws attention to and explains the URL on the toolbar. If the priority is low, which is the default case, no additional link appears in the toolbar and so the message does not concern a URL.

  6. For your changes to take effect, reset IIS.

    Note   Your changes might not have an effect on existing lists; to see their effects, you might need to create a new list.

Adding Custom Script that Accesses Page Elements in an Edit Form

To respond to events that occur by using controls in the form, you can add script to the page created in the browser by tapping into existing script blocks of SCHEMA.XML. For the NewForm type, the ClickOnce method in the ListFormOpening element is called when the user clicks Save and Close, but for the EditForm type, SubmitForm is called. You can add a custom method to a script block contained in the ListFormOpening element and add a call to your custom method from the beginning of the existing Windows SharePoint Services method. Both the ClickOnce and SubmitForm methods call the ValidateAndSubmit method defined in OWS.JS, a major JavaScript file used in Windows SharePoint Services. When the user clicks buttons within the form, methods in OWS.JS are called to complete the post. In addition, OWS.JS methods build the user interface for each field displayed in the form.

This example shows how to add script to validate a field that contains social security numbers, and script to display a message box acknowledging that an item has been added to a tasks list. As Figure 6 shows, if an incorrectly formed social security number is submitted in the form, a message box indicates that an invalid number is specified and the procedure to submit the form is exited. If the number is valid, as Figure 7 shows, the form is submitted and a message box acknowledges that the item is added to the list.

Figure 6. Error message that results from an invalid social security number

Figure 7. Message box that acknowledges that an item is added to the list

To add custom script that accesses page elements

  1. In Notepad or another text editor, open SCHEMA.XML in the appropriate Local_Drive:\Program Files\Common Files\Microsoft Shared\web server extensions\60\TEMPLATE\Locale_ID\Custom_Site_Definition\LISTS\TASKS directory.

  2. In the opening Fields element, make a small change to the order of the fields in the item form by moving the UserInfo and PercentComplete fields to the beginning of the form, interposing a new Field element between them for social security numbers, as follows.

    <Fields>
    <Field Type="User" List="UserInfo" Name="AssignedTo" 
    DisplayName="Assigned To"></Field>
    <Field Type="Text" Name="SSN" DisplayName="Social Security Number"> 
    </Field>
    <Field Type="Number" Name="PercentComplete" Percentage="TRUE" 
    Min="0" Max="1" DisplayName="% Complete"></Field>
    
  3. You can access current values contained by controls using the elements collection on the FORM element of the document object model, which returns an array containing references to all form elements. Use either the collection index or the name of an element as an indexer to specify a particular control (for example, document.forms[0].elements[elementName or index]).

    To ascertain the name or index of controls, you can iterate through the collection of page elements using the name and value properties of each element to display all names and values of elements in the form. Find the ListFormOpening element for either the EditForm or NewForm type, and temporarily add code like the following to the beginning of the ClickOnce() or SubmitForm() method, reset IIS, and then create a new item in the list to display all the names and current values of elements in the form.

    var j;
    var showControls="";
    
    for (j=0; j<document.forms[0].elements.length; j++)
    {
       showControls += document.forms[0].elements[j].name + 
          " == " + document.forms[0].elements[j].value + "\n";
    }
    alert(showControls);
    }
    

    Running this script reveals that you can use the following element names to refer to current values for fields displayed in the custom list item form for tasks lists:

    • urn:schemas-microsoft-com:office:office#Title
    • OWS:Priority:Dropdown
    • OWS:Status:Dropdown
    • OWS:PercentComplete:Local
    • urn:schemas-microsoft-com:office:office#AssignedTo
    • urn:schemas-microsoft-com:office:office#Body
    • OWS:StartDate:Date
    • OWS:StartDate:Hours
    • OWS:StartDate:Minutes
    • OWS:DueDate:Date
    • OWS:DueDate:Hours
    • OWS:DueDate:Minutes
    • urn:schemas-microsoft-com:office:office#SSN

    After you know which fields to reference, you're ready to delete this temporary example and add script to validate the new social security number field and display acknowledgment that the item was added. The script in this example uses the urn:schemas-microsoft-com:office:office#Title and custom urn:schemas-microsoft-com:office:office#SSN fields to return current values.

  4. Add code like the following to the beginning of the ClickOnce() or SubmitForm() method in the edit or new item form, which calls a custom ValidateField method and prevents form submission if the method returns false.

    var myCheck = ValidateField();
    
    if (myCheck == false)
    {
        return;
    }
    
  5. Add a method call to the end of the ClickOnce() and SubmitForm() methods immediately before the closing curly brace.

    AcknowledgeSubmission();
    
  6. Add the following method to the end of the script block immediately before the closing Script tag in both the edit and new item forms, which uses the test method of a RegExp object to perform validation on the social security number field.

    function ValidateField()
    {
        var ssnField = "urn:schemas-microsoft-com:office:office#SSN";
        var ssnBox = document.forms[0].elements[ssnField].value;
        var regEx = /^(\d{3})\-(\d{2})\-(\d{4})$/;
    
        var regx = new RegExp(regEx);
        var r = regx.test(ssnBox);
    
        if (r == false)
        {
            alert("Please specify a valid social security number.");
            return(false);
        }
    }
    
  7. To display a message box acknowledging that the item was submitted, add a function like the following after the custom method added in step 6.

    function AcknowledgeSubmission()
    {
        var listUrl = ]]></HTML>
    <ScriptQuote>
      <ListUrlDir WebRel="FALSE"/>
    </ScriptQuote>
    <HTML><![CDATA[;
      var columnName = "urn:schemas-microsoft-com:office:office#Title";
      var confirmPosted = "Thank you for adding \"" + 
      document.forms[0].elements[columnName].value + 
      "\" to " + listUrl + "\.\n\n";
      alert(confirmPosted);
    }
    

    The example uses HTMLCDATA partitioning and the ListUrlDir element with its WebRel attribute set to FALSE to return the full URL of the list, which in the resulting line of code in the browser is assigned to the listUrl variable. In other words, a complete line similar to the following is produced in the resulting page.

    var listUrl = "http://Server/sites/SiteCollection/Site/Lists/Tasks";
    

    In the form for editing items, you can change the previous confirmPosted string to a message that is appropriate for the context of making changes to items.

  8. After saving your changes to SCHEMA.XML, reset IIS so that they can take effect.

Conclusion

In this article, we suggested the following guidelines for customizing the forms used to work with list data in Windows SharePoint Services:

  • Use Web Parts and the Windows SharePoint Services object model to extend user interaction with list data, either bringing list views, for example, into the list item form, or bringing the list item form out to various locations in a site.
  • Customize ONET.XML to modify the top navigation area or to insert a Web Part by default within the home page of sites instantiated through the site definition.
  • Use custom Web server controls to consolidate code that you need to reuse in a deployment and insert the controls declaratively within the appropriate table cell of the page layout.
  • Customize the opening field collection of SCHEMA.XML to add special fields to the list and to change the order of fields as displayed in the list item form.

You may also use the following advanced customizations, involving customization of the form content defined in SCHEMA.XML to modify form views. However, these customizations may not carry over to future versions of Windows SharePoint Services:

  • Modify DispForm.aspx to customize navigation areas, but be strategic in customizations, always considering the table layout of the page.
  • Customize the form definitions in SCHEMA.XML to modify the view of list items displayed in a form, embed a Web Part in the form in lists created through the list definition, modify the toolbar, or add script in the browser page to enhance user interaction.

Considering these guidelines when you are customizing list item forms can help you extend user interaction with list data and help ensure code reusability in the deployment.

Additional Resources

Adding a Field to a List Definition
Creating a Basic Web Part
Customizing the Navigation Areas
Introduction to Templates and Definitions
Microsoft SharePoint Products and Technologies 2003 SDK