Please upgrade your web browser now. Internet Explorer 6 is no longer supported.
Thinking Web Solutions?
We create smart, fun, functional websites that make your web a better place.

How to Customize the User Information Page (3/3)

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(EventArgs
e)
{
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:

userinfo

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":

customprofilepage

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

23 comments for “How to Customize the User Information Page (3/3)”

  1. Tristan  10/30/2007

    Absolutely fantastic post! I felt the same way regarding modification of the OOB sharepoint files (as in Liam Cleary's solution), so this method seemed like an ideal approach. I have implemented something similar, and it works like a charm!

  2. Bruno Correa  10/30/2007

    Very good! It would be nice if you could post a Part 4, including a 'usermodify.aspx' page.

  3. VMAtm  10/30/2007

    Hi, Zac. How about part 4? Did you forget about it or not?

  4. Zac Smith  10/30/2007

    Definately havent forgot, its more a matter of finding the time to put the post together. Will endeavour to get something up in the next few weeks.

  5. VMAtm  10/30/2007

    Main question is - how to define SPControlMode for the controls are generating for the user property (for example, I need to show property value, but no need changes in this property) Wait for it with great respect :)

  6. Anders Jacobsen  10/30/2007

    An alternative to change the master would be to use an approach as I have suggested at: This implementation uses a HTTPModule to dynamically and non-intrusive change the Master and/or the CSS (http://www.pings.dk/blog)

  7. Fred  10/30/2007

    I tried a simple excludefields entry ' in ' under the defaulttemplates.ascx file and a IISreset...but that didn't seem to work... any reason why?

  8. ocean  10/30/2007

    Hello Zac, I have a question. I use aspnetsqlmemebership provider and form authentication, and I find no admin users have no rights to change their own user profile. and when I deployed your solution. admin users visit very well, but common user visit userprofile.aspx will get an unhandled error. can you tell me how to set the rights? thanks.

  9. Kieran  10/30/2007

    Hi Zac Did you ever get round to writing up anything on changing the OSSSearchResults.aspx page? You mentioned it in Part 1 but I dont see any other related posts. Many Thanks

  10. Mohamed  10/30/2007

    The links appear in the top of this post for Page 1 and Page 2 are broken, Could you link them to right article? Thanks.

  11. Sanjiv  10/30/2007

    I am getting the below error when I diplaoyed the code, Please let me know if I am missing anythinng else:- The directive 'control' is unknown. at System.Web.UI.TemplateParser.ProcessError(String message) at System.Web.UI.TemplateParser.ProcessDirective(String directiveName, IDictionary directive) at System.Web.UI.BaseTemplateParser.ProcessDirective(String directiveName, IDictionary directive) at System.Web.UI.TemplateControlParser.ProcessDirective(String directiveName, IDictionary directive) at System.Web.UI.PageParser.ProcessDirective(String directiveName, IDictionary directive) at System.Web.UI.TemplateParser.ParseStringInternal(String text, Encoding fileEncoding)

  12. Ben  10/30/2007

    so... how does this affect all other sites hosted on the SP box? What happens to your MS support agreement? What happens when a service pack updates this page... It's really Not a good idea to customise the OOTB admin pages in SP... Think MOSS instead with User Profile pages

  13. Zac Smith  10/30/2007

    Ben, I think you may have missed the key point to the whole article series. If you actually read through and understand the method of customization you will see that this solution does not affect any of the OOTB admin pages. It does not affect other sites hosted on the box, it should not affect your MS support, service updates are no problem. I don't see how suggesting MOSS is a solution - for many people MOSS is not a viable option.

  14. Frederik  10/30/2007

    Its a great example but im missing something. In this line you redirect to useredit.aspx but where is the ID?

  15. Frederik  10/30/2007

    Sorry! The line is meant to the line where you set up the Edit Item button. You onlu redirect to the useredit.aspx, but you need a ID of the user

  16. Zac Smith  10/30/2007

    Yes that was a bit of an oversight in the example - I have updated the post to address this issue.

  17. Shridha Agarwal  10/30/2007

    Hi Zac ! You seem to have forgotten the part 4 of the series. Waiting for it.

  18. Brian Johannesen  10/30/2007

    Hi Zac , great articles you made here.. Hope you will have time to do the 4th one as well :)

  19. Tom K  10/30/2007

    Zac - a thousand thanks! All roads I could find on this matter keep coming back to you ... a great testament to your solution :-) To note, with regards to Visual Studio 2010 (beta, at least at the time of this writing) ... when I import your solution the Microsoft.Sharepoint assembly gets 'disabled' of sorts ... only after reimporting (from the \\Program Files\Common Files\Microsoft Shared\Web Server Extensions\12\ISAPI folder) and upping the Target Framework to 3.0 or 3.5 will your solution properly build. Just an fyi for anyone who may have been traveling down the road I was ... Thanks again! Looking forward to part 4! :-)

  20. santhosh  10/30/2007

    Thanks for the post. I wanted to exclude Account from the list. But not able to do that.I could exclude all other fields . Is there any workarounds? Thanks

  21. Dan G  10/30/2007

    That's a cool solution, just started using Sharepoint and must admit the customisation side of things is a right pain.

  22. jblaph  5/9/2011

    Zac, Thanks!, the post is great and is exactly what I 've been looking in the internet.
    It's a pity the link with the source code is not working.

    Do you think can you fix the link or provide using another way?

  23. Zac  5/17/2011

    Really sorry guys but I think the file was left behind when we last moved servers. I will have another look but it's likely gone.

Post a comment