UPDATED: Changed the Edit Button to override the default SP edit
button to fix edit link bug. The sample solution has been updated
to reflect the changes.
Continuing on from the User Information page customization
series:
Part
1 talked about some of the difficulties presented with
application pages in general.
Part
2 demonstrated how to redirect the user to a custom User
Profile page using feature deployment.
This part will show how you can simply customize the look and
feel of the User Profile page. Before reading this part you should
read Part 2 and have a look at the sample code.
I am going to focus on the more significant changes - all the
HTML/CSS changes including the custom master page have been left
out (The code used is included in the sample solution though).
In order to reuse as much of what SharePoint provides as
possible - I will base my customized User Profile page on the
SharePoint userdisp.aspx page.
The first thing to do is to turn the userprofile.aspx page
created in Part 2 into code behind page that extends the
UserDisplayEditPageBase. To do this, create a class like so:
public class
UserProfilePage :
UserDisplayEditPageBase
To resolve the UserDisplayEditPageBase class you need a
reference to Microsoft.SharePoint.ApplicationPages.dll which is not
in the GAC. You will need to Browse to the location "C:\Program
Files\Common Files\Microsoft Shared\web server
extensions\12\CONFIG\BIN" to find this dll.
I have included the dll in the sample source code for
simplicity.
Now I will update my custom profile page to inherit from this
class:
<%@ Page
Language="C#"
Inherits="CustomUserProfile.UserProfilePage,
CustomUserProfile, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=1ba1bfabc83c4398"
MasterPageFile="/_layouts/application.master"
%>
Note that that I have used the fully qualified name and this
assumes that the dll will be signed and placed in the GAC. See the
sample solution for how this can be easily done.
Now put the contents of the original userdisp.aspx (from the 12
Hive) into the userprofile.aspx page. The first modification to
make is to remove the delegate control in the custom page or so you
don't get stuck in an infinite redirect loop.
At this point I could just apply a custom master page and be
done. This would let me easily apply a new look and feel, but I'd
like to make a few modifcations to the layout as well.
You will probably have already noticed that the guts of the page
are contained in a FormComponent control. This control provides a
set of properties and methods that make it easy to display a form
based on a SharePoint list item. It's rendering is controlled by
the TemplateName property which is currently set to 'UserListForm'.
We can find the contents of this form by looking in c:\program
files\common files\microsoft shared\web server
extensions\12\template\controltemplates\DefaultTemplates.ascx. I
don't want to modify this file directly (it will affect all
SharePoint sites) so I will take a copy of the
SharePoint:RenderingTemplate and put it in a new ascx file named
CustomTemplates.ascx (this will live in the controltemplates dir).
I then give it a custom name so that it only overrides it for the
profile display page. Now I should have a FormComponent in my
profile page like:
<SharePoint:
FormComponent
id="UserListForm"
TemplateName="CustomUserListForm"
ControlMode="Display"
runat="server"/>
and in CustomTemplates.ascx file I have:
<SharePoint:
RenderingTemplate
ID="CustomUserListForm"
runat="server">
<Template>
<span
id="part1">
.....
Note that the TemplateName of the FormComponent matches up with
the ID off the RenderingTemplate.
From here it is easy enough to edit some of the basic HTML
elements of the form.
Next up is to customize the Toolbar. To do this copy the
RenderingTemplate with the ID of "UserInfoListDisplayFormToolBar"
from DefaultTemplates.ascx to the CustomTemplates.ascx file. I want
to remove some of the buttons and have a custom Edit Item button so
I can link to a custom user profile edit page. To do this change
the control declaration from:
<SharePoint
:UserInfoListFormToolBar
runat="server"/>
to
<SharePoint
:FormComponent
id="UserToolBar"
TemplateName="CustomUserInfoListDisplayFormToolBar"
runat="server"/>
And then customize the RenderingTemplate like so:
<SharePoint
:RenderingTemplate
ID="CustomUserInfoListDisplayFormToolBar"
runat="server">
<Template
>
<script>
recycleBinEnabled =
<SharePoint:ProjectProperty
Property="RecycleBinEnabled"
runat="server"/>;
</script>
<wssuc
:ToolBar
CssClass="ms-toolbar"
id="toolBarTbl"
runat="server"
FocusOnToolbar="true">
<Template_Buttons
>
<prof:UserProfileEditButton
ID="UserProfileEditButton1
"
runat="server
" />
<SharePoint
:UserInfoListDeleteItemButton
ID="UserInfoListDeleteItemButton1"
runat="server"/>
</Template_Buttons
>
</wssuc:
ToolBar>
</Template
>
</SharePoint:
RenderingTemplate>
Note that I have removed a few of the buttons for alerts and
regional settings as well as create a custom button for linking to
the useredit.aspx.
The custom edit button simply overrides the standard SharePoint
edit button and updates the URL:
public class
UserProfileEditButton:
UserInfoListEditItemButton
{
protected override void
OnLoad(EventArgse)
{
base.OnLoad(e);
base.NavigateUrl =
base.NavigateUrl.Replace("useredit",
"usermodify");
}
}
Next I want to tidy up up the user display name as it includes
the domain and won't have any meaning for most users.
To do this I override the OnPreRender method in the
UserProfilePage class created earlier:
protected
override void
OnPreRender(EventArgs e)
{
base.LabelTitle.Text =
base.UserListForm.ListItem.GetFormattedValue("Title"
);
}
This will give us a nicer looking display name:

In this case I don't want to display the SIP Address, so the
next task is to remove this from the profile page. Currently all of
the fields are rendered using a FieldIterator which is declared on
the page as:
<SharePoint:ListFieldIterator
runat="server"/>
In order to customize how the user list fields are displayed -
we need to create a class that overrides the ListFieldIterator. My
class is declared like this:
public class
UserProfileFieldIterator :
ListFieldIterator
Becuase I want to exclude the SIP Address I am then going to add
override the IsFieldExcluded method like so:
protectedoverride
boolIsFieldExcluded(
SPField field)
{
if (field.Title ==
"SIP Address")
return
true;
return
base.IsFieldExcluded(field);
}
To replace the existing field Iterator currently being used I
need to first register the assembly:
<%@ Register
TagPrefix="prof"
Namespace="CustomUserProfile"
Assembly="CustomUserProfile, Version=1.0.0.0,
Culture=neutral, PublicKeyToken=1ba1bfabc83c4398"
%>
and then replace the field iterator declaration with the custom
one just made:
<prof:UserProfileFieldIterator
ID="UserIterator"
runat="server"
/>
The last thing I'm going to do is attach the custom master page.
This is simply a case of changing userprofile.aspx to point to a
new master page:
<%@ Page
Language="C#"
Inherits="CustomUserProfile.UserProfilePage,
CustomUserProfile, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=1ba1bfabc83c4398"
MasterPageFile="/_layouts/customprofile.master"
%>
The custom master page also requires a couple of css files to
override and add styles to the SharePoint page.
And now after all our hard work - "The final product":

You can download the sample code (including solution deployment)
->
here.
Although I have only customized the SharePoint user info page
you can do the same for the edit page - or any application page
really.
I am considering doing a Part 4 with some advanced
customizations such as having a custom action when closing the page
(eg redirect) and modifying some of the form fields. Let me know if
this is something that you are interested in.
For more information on Form Components, Rendering Templates and
List Iterators have a look at the following resource:
http://msdn2.microsoft.com/en-us/library/aa544154.aspx