Customizing the User Experience of SharePoint: Lists, Custom list forms, and CAML Views (Part 3 of 6)
Finally, after a very, very, very, vey, very, very long break, here is part 3 of the “Customizing the User Experience of SharePoint” series. This article also launches the SharePoint User Experience week here on SharePoint Magazine. One full week, focusing only on understanding SharePoint architecture from a user experience point of view. It doesn’t get any better than this.
The Customizing the User Experience of SharePoint series aims to explain how the user experience works, from how the interface is built down to details on how columns of lists get created.
The series is also an exclusive preview of the topics from my upcoming book, “Building the SharePoint User Experience”, which deals with SharePoint user experience for 350 pages. Actually, as with this series, the book explains the SharePoint architecture from a user experience perspective.
Here is an article outline for the six parts:
Part 1: Overview of the default SharePoint interface from a technical point of view
In the first article we will look at how the default SharePoint interface is built. We will look at a site, going from top-down, explore some of the the default lists, the fields used to create the basic field types, which content types are available, and how list forms are rendered.
Part 2: Modifying the default experience
This article will show you which options are available for you to modify and improve the default setup. Learn how to override the default rendering of fields or forms without voiding your supported state.
Part 3: Lists and custom list forms
The third article will cover the basics of customizing lists using different views, custom list forms, and fields.
Part 4: Content types user interface
The next article will explore how you can utilize content types to display different input forms and display forms.
Part 5: Custom fields deep dive
Ever wanted to create a new field type? SharePoint enables you to do this and it is a very powerful tool for customizing the user experience.
Part 6: Fast track to feature generation
Writing custom lists with content types by hand can take a massive amount of time. In the final installment I will share with you some tools and techniques that makes list, field, and content type generation very fast.
A Short Recap
It’s been a while since the last article, so I thought that at least I should post a short recap of where we have been, in case you cannot be bothered to read Part 1 and Part 2.
In the first part we examined how a site was built from various different XML files, including webtemp.xml, onet.xml, and the global site definition. We then briefly touched on list templates, content types, list forms, columns and fields, and views, mostly to know what was ahead.
In the second part we looked at some methods we can use to customize the default user experience and learned what will break out supportability. We examined CustomActions and saw how we can override ControlTemplates to modify how visual elements of a SharePoint site are rendered. I also mentioned two other articles here on SharePoint Magazine that deal with custom master pages and feature stapling.
On that note, however, I would like to point out that these methods are not your only options for customizing the default user experience. One thing that really deserves more attention is DelegateControls, a method by which you can add content to a page using a feature. This is how Search Server and MOSS changes the search box and adds ‘My Site’ and ‘My Links’ as well as the publishing console.
Back to lists.
Lists and List Templates
When I talk to developers, and especially developers who are new to SharePoint, talking about lists is a bit confusing. First, lists seems to be a somewhat ambiguous term, sometimes referring to lists and sometimes referring to list templates. Before we dive into details I want to just make sure you are up to snuff on the difference.
A list template is a template for how new list instances will be created. A list template holds most of the content which will make up the lists, including the default columns, permissions, views, content type bindings, and forms. When you go to the Create page of a SharePoint site, the columns you see, with the exception of the Web Pages column, are filled with the default List Templates that get deployed as part of the Team Collaboration Lists feature.
That last statement is important; the list templates get deployed using features. While you have the option of defining list templates as part of a site definition, you don’t want to do that. If you watched the SharePoint blogosphere a few months back there was a gentle reminder from absolutely every sane person alive to keep as little as possible inside the site definition. I think Andrew Connell has a very nice explanation of why you want to keep stuff in features and leave your site definitions as small as possible.
List instances, on the other hand, are what you create when you click one of the templates on the Create page. These are, as the name implies, instances of the list templates. You store data in a list instance, and this is also where you would add columns, attach workflows to items, etc.
You can deploy list instances using features, and this makes a lot of sense when you are creating a SharePoint solution in which you need to store data for your solution. However, your options for customizing a single list instance through features are a bit limited. For example, you cannot define additional columns to a list using an elements.xml file, nor can you add or modify views in a feature. At least not unless you add a feature receiver and modify the list instance using code.
With these distinctions out of the way, let’s get into the details of how these elements are built and how we can manipulate how the users experience our lists.
List User Experience Options
Users interact with lists using two visual interfaces, the list forms and the views. These are in fact closely tied together as we will see in a moment.
List forms
A list form is a regular ASP.net page the serves as the visual interface of a list. List forms are defined in the list template, but the forms are instantiated in a list instance. This means that we can override the list forms for each list by customizing the list forms that are instantiated with the list.
The list form definitions tell SharePoint from where each list form should be instantiated. If you examine the Custom List list template, located in the [12]\TEMPLATE\FEATURES\CustomList\CustList\schema.xml file, you can see the Forms section near the bottom:
Each of the Form elements you see here represents one state or display mode of list items, as specified in the Type attribute. The Url attribute defines the list-relative Url where the list form will be instantiated. I’ll skip the SetupPath for a moment and tell you that WebPartZoneID defines which webpart in the ASP.NET page should hold the contents of the list form.
The SetupPath tells SharePoint what should be the source of the list form. As we saw in the first part of the series, SetupPath is relative to the [12]\TEMPLATE folder, so if you open [12]\TEMPLATE\pages you should see a file called form.aspx. If you don’t, well, you’re either in trouble or you know extremely well what you are doing. If you open that file you will notice that it is indeed a very normal ASP.NET file. No magic here.
One really important thing to note, however, is that until you decide to customize a list form the form will still point to the source. Changes to the pages\form.aspx will reflect on every list form that still points to the original source.
If you decide to create your own list templates, however, you may point your list forms elsewhere. In that case you would likely replace SetupPath with Path, since Path is feature-relative, while SetupPath is [12]\TEMPLATE relative.
You may want to change a list form for a specific list instance. You now know that each of the list forms gets virtually stored in the path specified in Url attribute. These form pages can be customized using the customization framework of SharePoint. If you haven’t worked with this before, here’s the executive summary:
When you customize a page, meaning you change the ASP.NET code, SharePoint will unlink the page from the source, and copy the page into the SharePoint database. Then, al changes you make to the customized page gets written to the database instead of the source file. SharePoint will keep track of whether your page is customized and retrieve the page from the correct source.
To perform such a customization the easiest method is to grab a copy of SharePoint Designer, or SPD for short. SPD is tightly integrated with SharePoint and fully supports working with customized files. When you start SPD and connect to your site you will be able to browse into the list containing the form you wish to customize. Simply double-click any of the forms to open it and the hit Save to customize the form and remove its link to the source pages\form.aspx. SPD will warn you about customizing forms, but after you click Yes to acknowledge the warning, you are free to modify the list form as you see fit.
You can also define a completely new ASP.NET page to take over any of the existing list forms. This is done, in SPD, by going to the list properties and selecting Supporting Files where you will be allowed to browse for a different page. If you want to do this you must make sure that the new page contains the correct list form to use for the corresponding display mode, either NewForm, DisplayForm, or EditForm. To insert such a form on a page, place the cursor where you want the new form and go to Insert->SharePoint Controls->List forms.
You may not immediately realize that this is a cool thing, but consider this: You can link your list forms to a page stored in a library. That’s right, suddenly your list forms are editable from the web interface, allowing you to customize the user experience of modifying data in SharePoint, all through the web interface.
No more using SPD every time you want to modify the list forms. Cool, eh?
Of course, such an approach carries significant security issues, so you would need to limit permissions to the forms page library or pages. But you should know you have the option.
Speaking of content, which we weren’t, but I need a segue, where do the actual form content enter the scene? All the form elements derives from the same form.aspx source page, so there must be something that tells SharePoint which columns to put into which forms. The answer will be discussed more in part 4, however for now you should know that the actual form, meaning the columns, are not rendered from the list at all, but rather from the content types.
Content types carry their own set of forms that are used to render the display, editing, and new forms for items based of the content type. The cool thing about this is that you can tie the rendering of items to the type of item, not on where it is stored. Override the default forms used and you can create visually stunning displays. Here’s one example I have in the book “Building the SharePoint User Experience”:
You’ll learn how to create content type specific forms in the next art of the series. Note that the title is made using a custom field type, which will be covered in part five.
Views
Your other option for customizing the user experience of list is views. You’ve probably worked with view through the web interface. Basically it is a view of data of a list, such as the AllItems.aspx view, which shows all items or documents in a list.
Strictly speaking, AllItems.aspx is a view page, not a view. The view is All Items, or, as in the previous screenshot, All Documents, but it is displayed on a view page.
These views are declaratively defined in the list template, in the Views section of the schema.xml file. This section defines any views that are available by default for new list instances based on the template. In addition you can create new views after the list has been created either by using the web interface, or, as developers, through code.
However, some more advanced aspects of view creation can not be handled through code or the web interface at all. I am, of course, talking about the dreaded CAML View schema.
CAML view creation
Now, before you go hiding in the closet, swearing not to exit before I promise not to talk more about views, let me calm your fear of custom view development by saying that we will not be doing anything really advanced here. A lot of developers have a natural fear of SharePoint custom view development. However, if you beak down views into manageable chunks, creating custom views is no harder than learning to ice skate. Yes, it is painful the first times you fall, but once you get the hang of it is great fun. And cold. And hard. Oh, well…
Open the Custom List schema.xml, located in the [12]\TEMPLATE\FEATURES\CustomList\CustList folder. Close all elements except the Views element. Next, close the View element with BaseViewId=”0”. This is the default view that is used when you add a list view to a web part using the web interface. By the way, if you create your own list template and you’re unable to add lists based on that template to a web part page you are most likely missing the BaseViewId=”0” view. The error message would be ‘Unable to add selected web part(s). [List name]: List View Web Part could not be added, list may be hidden.
Next, inside the View with BaseViewId=”1”, close the first-level child elements. These would be GroupByHeader, GroupByFooter, ViewHeader, ViewBody, ViewFooter, PagedRowset, PagedClientCallbackRowset, PagedRecurrenceRowset, RowLimit, ViewEmpty, Toolbar, ViewFields, and Query. These elements are what constitutes a view. The good news is that quite often you wont need to deal with all of these, only 4-5 are really necessary. The bad news is that dealing with any of these requires you to write View CAML.
When you feel brave enough, open the ViewBody element, and I’ll walk you through the basics.
ViewBody, by the way, is called once for each list item in our list. This is in contrast with other View elements, such as ViewHeader and ViewFooter, which are called only once.
The Views of a list are usually used to output the HTML we need to send back to the browser, so if you keep thinking that we are building a HTML document it can be a bit easier to wade through all this stuff. And, since the View schema is completely XML based, we need to adhere to XML rules. This means that whenever we want to include plain HTML we must encapsulate that HTML in a CDATA element. This is exactly what happens in the first line (1505) where we say that we want to output HTML and then contain the actual HTML inside a CDATA element.
Our HTML so far is ‘<TR CLASS=”’
Output, variables and conditions in View CAML
Next we pick up a variable using the GetVar element. The Name attribute tells SharePoint which variable to get, in this case AlternateStyle. Now, in this example, the first time we enter the ViewBody, which would be for the first list item, this value would be nothing or null since it is a custom variable and we need to set this ourselves. This will happen in this example in a few moments.
Immediately following the GetVar element is a new HTML element which outputs “>. So, for the first item in the list, the HTML output so far would be ‘<TR CLASS=””>’.
The IfEqual element that follows is a conditional element. For the IfEqual element we need at least three child elements, the Expr1, Expr2, and Then elements, and we may add an optional Else element. The structure is just like a normal conditional element from any other language. We evaluate Expr1, compare that to Expr2 and if these are equal, perform whatever is in Then. If the values are not equal and we have an Else element, as it the case here, perform whatever is in the Else element. If we don’t have a Then element, nothing happens if Expr1 is not equal to Expr2.
Basically, this is the same as writing
if (Expr1 == Expr2) {
<Then>
}
else {
<Else>
}
In our view the Expr1 and Expr2 compares the variable named AlternateStyle to see if it is set to ‘ms-alternating’. If it is, the Then element will set the variable, using the SetVar element, to nothing. Else, meaning the AlternateStyle is already set to nothing, set the AlternateStyle to ‘ms-alternating’ for the scope of this view request. the effect of this is that we alternate for each item whether we output the string ‘ms-alternating’ when we call ‘GetVar Name=”AlternateStyle”’ in line 1505. Or, in plain C#, given that we have a HTMLWriter object called writer, a string called AlternateStyle and an SPList called list:
foreach (SPListItem item in list.Items)
{
writer.Write(“<TR CLASS=\”");
writer.Write(AlternateStyle);
writer.Write(“\”>”);
if (AlternateStyle == “ms-alternating”)
{
AlternateStyle = “”;
}
else
{
AlternateStyle = “ms-alternating”;
}
}
The next CAML element is Fields, which starts on line 1520 and ends on line 1541. As for the ViewBody, Fields is called for each Field, or column, in the list item on which we are currently working. We thus start the rendering of each field, or column, by outputting <TD Class=”. Next two FieldSwitch elements, which are just switch conditionals, output either ‘ms-vb-title height=”100%’, ‘ms-vb-icon’, ‘ms-vb-user’, or ‘ms-vb-2’ depending on the ClassInfo property of the field, as well as the Type property and whether Presence is enabled. I won’t go into all the details and recreate a C# statement here, but you should be able to deduce the output. After the switch we output “> to finish the TD we started in line 1520.
However, more importantly, line 1540 outputs the field itself. The logic of exactly what will be output here depends on the field itself, and we’ll get back to that in part 5. For now you can assume that Field outputs the value of the field as it is accurate enough to understand what goes on.
Finally we close the TD html tag we started in line 1520 and, after completing the Fields iteration, close the TR html tag we started in line 1505.
Phew, that was a mouthful, however, the basic concept is that we build HTML for each list item. In this case a TR with a TD for each column. You can, of course, make this a lot simpler if you don’t want or need all the styling and conditions. As such, to just output a TR for each list item and a TD for each column, you might do just:
<ViewBody>
<HTML><![CDATA[<TD>]]></HTML>
<Fields>
<HTML><![CDATA[<TD>]]></HTML>
<Field/>
<HTML><![CDATA[</TD>]]></HTML>
</Fields>
<HTML><![CDATA[</TR>]]></HTML>
</ViewBody>
which is a lot less complex.
See? Custom view development isn’t really that hard. And if you want to learn more, start by creating your own list template and build views from scratch. There is also a complete chapter in my new book which deals with more advanced concepts of custom view creation, and in my completely unbiased opinion I highly recommend that book to learn CAML view development
Where to now?
Now that you have seen a bit on how you can use lists to tailor the user experience, you might want to explore a bit further on your own. Here are some resources which might help you along:
The MSDN documentation for CAML view schema is the most comprehensive documentation available. You get all the gritty details for all the root elements in a view as well as all the rendering elements. However, be advised that not all aspects of the documentation is as clear as can be, and some information is missing or plain wrong.
If you want a comprehensive guide there is a separate chapter in my book “Building the SharePoint User Experience” that covers views and takes you on a guided tour through creating a view using all the aspects of view creation, including sorting, grouping and paging.
Microsoft Office Online has a nice guide for walking you through setting up a new custom list form page.
And, of course, make sure you read the next part of this series where we will dive into content types and how you can modify appearance of certain types of information.
I do hope I’ll see you again for the future parts of this series,
.b



23. Feb, 2009 








Author