Sunday 16 March 2008

Great controls to be aware of when building SharePoint sites

Something I've been meaning to do for a while is discuss some of the controls I've found useful when putting together SharePoint sites. Obviously before building a custom control for a specific behaviour, it's a good idea to check if SharePoint comes with anything that will do the job. It sometimes surprising what you find! Certainly those from a Content Management Server background will be familiar with the idea of having lots of reusable controls (which used the CMS API) within the team, but in MOSS some of the equivalent controls come for free. The most obvious is the Content by Query web part (though we won't mention that the output HTML isn't accessible [WCAG AA-compliant] without extra work), but some of the smaller controls deserve some attention too. So here's a rundown of some handy items for the toolbox:

SPSecurityTrimmedControl

This control can be used to selectively display content or controls depending on the current user's SharePoint permissions. Whatever is the inner content of the control will therefore not be shown if the user doesn't have the specified permissions. An example would be:

   1: <SharepointWebControls:SPSecurityTrimmedControl runat="server" Permissions="ManageWeb">
   2:     This is only visible to users who can manage current web..    
   3: </SharepointWebControls:SPSecurityTrimmedControl> 

In addition to the Permissions property shown above (enum), the PermissionsString property can be used to specify a comma-separated list of required permissions. This can be used in conjunction with the PermissionsMode property which takes 'All' or 'Any', and also the PermissionContext property which specifies what SharePoint object (e.g. 'CurrentList', 'CurrentFolder', 'CurrentItem', 'CurrentSite', 'RootSite') the specified permission applies to, so it's flexible. Examples of the permissions which can be specified include 'ManageLists', 'AddListItems', 'ViewPages', 'ManagePermissions' and so on. These are members of the SPBasePermission enum and Zac Smith has a full list. Notably many of these permissions are probably more useful in a collab scenario rather than WCM. [UPDATE: Text in this section updated following comment below/further testing:] For WCM folks the control does look like it does something useful in being able to filter on authentication type - unfortunately this doesn't work as advertised. For reference (in case MS fix it), the usage is:


   1: <SharepointWebControls:SPSecurityTrimmedControl runat="server" AuthenticationRestrictions="AnonymousUsersOnly">
   2:     This *should* be visible only to anonymous users but it doesn't work..    
   3: </SharepointWebControls:SPSecurityTrimmedControl> 

As you'd expect, valid values here are 'AnonymousUsersOnly', 'AuthenticatedUsersOnly' and 'AllUsers' - however as noted in the comments below 'AuthenticatedUsersOnly' is the only flag which seems to work properly.

There are some other interesting properties too:

  • PagesMode - valid options are 'Design', 'All' and 'Normal'

  • QueryStringParametersToInclude

  • RequiredFeatures

These look like extra properties to filter on, but alas I couldn't get these to work either. My investigative powers let me down here as firing up Reflector onto both SPSecurityTrimmedControl and the related RightsSensitiveVisibilityHelper class didn't give anything away in terms of usage, nor did Google or searching the 12 hive. Certainly it looks like specifying values is all that would be needed for latter two parameters, but I had no joy. A final consideration for SPSecurityTrimmedControl however, is the idea of further possibilities opened by deriving from this control in the same way SPLinkButton does.

EditModePanel

Where the previous control examined the user's permissions to establish whether content should be shown, the EditModePanel looks at whether the current page is in display or edit mode. This can be incredibly useful in the WCM world for displaying help messages or other content to users as they edit a page. However there are other uses - hiding navigation, adding inline CSS override classes to use different formatting (particularly useful) and emitting debug information in the HTML output are all examples. The declaration for this control would look like:

   1: <PublishingWebControls:EditModePanel SuppressTag="false" GroupingText="Title help" 
   2:         PageDisplayMode="Edit" runat="server" id="EditModePanel1">
   3:     Page titles should be concise
   4: </PublishingWebControls:EditModePanel>

At run time in edit mode, this would look like:


EditModePanel

A prettier usage might be to include the field controls within each respective EditModelPanel, meaning the input control is shown within the borders of the box. To do this we'd also need an extra EditModePanel set to PageDisplayMode="Display" which also contained the field control, since the original will display in edit mode only. Note this control will output a surrounding <div> unless the SuppressTag property is set to 'True'.

ListItemProperty

One control you might use in conjunction with the previous control is the ListItemProperty control. This simple little fella allows you to write out a particular field's value for a list item. The field which is rendered is specified with the Property attribute, where we specify the field's internal name. By default, the current list item (i.e. for the page we're viewing) is used, but this can be overridden by specifying the List property - to do this we specify the list GUID with braces:



   1: <SharePointWebControls:ListItemProperty runat="server" id="ListItemProperty1" 
   2:     List="{C110296D-2BE9-4818-80EE-A06BD018DE2F}" ListItemID="1" Property="Title"/>


I think of this control as doing a .ToString() on the contents of the chosen field. This can sometimes be useful in WCM where you want the value to appear in a different location onthe page to where it is edited - for example within a <title> tag. Note we can also specify the version of the list item we want to retrieve the value for with the ListItemVersion property.

ListProperty

Much the same as ListItemProperty except on a list itself. These two may well be used together as the code in a list's DispForm.aspx does:



   1: <SharePoint:ListProperty Property="LinkTitle" runat="server" id="ID_LinkTitle"/>
   2: : 
   3: <SharePoint:ListItemProperty id="ID_ItemProperty" MaxLength="40" runat="server"/>

This will show the current list's title, followed by a colon, followed by the current list item's title.


ProjectProperty


Slightly confusing name, but this control allows us to write out some properties of the current site/web. The MSDN documentation shows the valid list to be:

  • BlogCategoryTitle - Category of the current post item

  • BlogPostTitle - Title of the current post item

  • Description - Description of the current Web site

  • RecycleBinEnabled - 1 if the recycle bin is enabled; otherwise, 0

  • SiteOwnerName - User name of the owner for the current site collection

  • SiteUrl - Full URL of the current site collection

  • Title - Title of the current Web site

  • Url - Full URL of the current Web site
So the following would write out the title of the current web:



   1: <SharePointWebControls:ProjectProperty runat="server" id="ProjectProperty1" 
   2:     Property="Title" />

DelegateControl

This control provides an architecture where an 'outer' control is added to the page layout/master page, but the 'inner' control is determined by a Feature, thus allowing the control to be swapped out without having to modify the original template. This is used widely in Microsoft's master pages. This is a great control, I discuss it more fully in my Using the DelegateControl post.

AssetUrlSelector

To finish on something slightly different, this control can be invaluable when developing custom web parts and field controls. It provides the 'file picker' experience authors are used to when working with SharePoint, and fits well when you have a control which requires a file to be selected. So in several of my controls I allow the user to override the XSL file used for formatting, and the AssetUrlSelector is added to the user control I use for the edit view of the control. This provides me with the 'browse' button which will launch the picker when clicked:


AssetBrowseButton 
Clicking the button then shows:

AssetUrlSelector 
The AssetUrlSelector provides a fairly good user experience, including opening the picker in the location of the currently-selected file if one exists, or defaulting to a specified default location if not. Along similar lines if you need to provide a slick experience to select an image is the RichImageSelector - this is the picker used by the RichImageField control.

Summary

So that's some of the controls I've found useful. Obviously there are stacks more and the ones I did highlight can be used in lots of interesting ways which aren't discussed here. But hopefully this does serve to remind you to check what's in the box before spending time writing your own!

17 comments:

Anonymous said...

At least I haven't overlooked a SharePoint column type of AutoIncrement, since it would appear there is no such animal in SharePoint 2007.

Anonymous said...

Really useful post, thanks Chris. Can you recomend a good place in the SDK or MSDN to start exploring all the available publishing controls?

Chris O'Brien said...

Cool, thanks for the feedback Matt. Unfortunately the documentation is still a bit sparse for some of the controls - often the best thing is to drag the control onto the template in SPD and start exploring the properties - where the property takes an enum, IntelliSense should appear to help you out with the values.

However, it is definitely worth checking the documentation in case - the controls listed here are either in the Microsoft.SharePoint.WebControls namespace or Microsoft.Sharepoint.Publishing.WebControls namespaces - recommend taking a look.

P.S. I notice the contents of tags within my code samples has disappeared - hopefully doesn't lose too much value of the examples, will rectify as soon as I can :-)

Willem du Preez said...

Nice one Chris. Very useful! I was just about to role my own SPSecurityTrimmedControl.

Will

Anonymous said...

I have listed all the SPSecurityTrimmedControl flags here
http://www.wssdemo.com/Blog/archive/2007/12/22/display-content-based-on-access-rights-much-easier-in-wssv3.aspx

You can also use the ddwrt:IfHasRights(permissionMask) function in any of the XSL based web parts (Data View, Content Query etc). See http://www.wssdemo.com/Blog/archive/2007/12/22/sharepoint-data-view-conditional-formatting-based-on-user-permissions.aspx

Chris O'Brien said...

Thanks Ian. Liking the tip on ifHasRights() in XSLT a lot :-)

Anonymous said...

Very nice article, however I have a question: is it possible to install a feature with Control in it, which works in such manner, that after rendering itself it "calls" a delegate control with next Sequence value?

Anonymous said...

Chris:

I hope you are still checking this blog. Thanks for the great information, however I am having problems using the SPSecurityTrimmedControl when using the Authorization modes. For example:

SharepointWebControls:SPSecurityTrimmedControl runat="server" Permissionsstring="Anything"

works great, I am doing this for anon vs authenticated users and showing particular web part zones. However, when I try this:

SharepointWebControls:SPSecurityTrimmedControl runat="server" AuthenticationRestrictions="AnonymousUsersOnly"

Or AuthentictedUsersOnly, either way, it doesn't seem to work at all. I basically need to show and hide web parts if you are anon or authorized and the permissionsstring works fine, but I can't get the AuthenticationRestrictions to work, any ideas? I am doing this in a Page Layout, around WebPartZones and it is a sub site collection but I can't see how that would matter - - why would permissions work but AuthorizationRestrictions not? I have been fighting with this one for a while now. I know the user is not authenticated for example, because when they click on a list, they are prompted to log in and its appearent through the "limited access" role they have when using the permissionString attribute.

Any help or ideas?

Great article and keep up the good work.

Chris O'Brien said...

Hi,

You should be able to work with the DelegateControl in code yes - you would set the 'ControlId' property and call the Render() or RenderChildren() methods to get the output.

However, I don't think you can arbitrarily set the sequence - the control will automatically load the control which has been registered for this ID with the lowest sequence, and that's the control you'll get rendered.

HTH,

Chris.

Chris O'Brien said...

@Martin,

I've just gone back to check using the 'AuthenticationRestrictions' property of SPSecurityTrimmedControl. Interestingly, I see the same behavior as you - works fine for authenticated users, but I get no output whatsoever for anonymous users.

Looks like a bug in the control I'm afraid :-(

HTH,

Chris.

Anonymous said...

Thanks Chris:

At this point, I'm at my wits end with MOSS. I had a way around this problem, at the end of the day I needed a way to show and hide based on authentication status.

So I created my own webcontrol/compositecontrol and used ParseChildren(false) and then didn't render the child controls based on authentication status.

While my implemenation and design works great, now SPD (SharePoint Designer)has ruined the party :(. For whatever reason if I wrap a WebPartPages:WebPartZone in ANYTHING besides the SPSecurityTrimmedControl, it will not render in SPD, at the MOSS UI, .Net or browser it works fine.

However, we do Page Layouts in SPD and our designers need to access pages through it - - since the zones don't render when wrapped in my control, we can't do this either.

I have looked at the SPSecurityTrimmedControl via reflector and done everything I can think of, right now, if you want to do WCM on WebPartZones, I see NO WAY to do it start to finish, without the UI or SPD breaking. If you are curious, the error I get from SPD is

"WebPartPages:WebPartZone can not set property ZoneTemplate"

What drives me mad is the SPSecurityTrimmedControl can wrap a WebPartZOne, but I can't get anything else to render in SPD....sigh

If you or anyone has come up with a steadfast way to do WCM on web part zones for Authenticated vs Anon please let me know.

Thanks for your reply

Martin

Chris O'Brien said...

Hi Martin,

Hmm, that's a conundrum alright. I also just had a peek with Reflector and went down the same path as you with IDesignerEventAccessor (I found your newsgroup post). I take it you've now implemented this in the same way as SPSecurityTrimmedControl and the control still doesn't render in SPD?

Other thoughts:-

- Is the assembly in the GAC so we know it's not a permission issue?
- Have you tried stepping through the code when SPD runs the control code? You'll need to attach to the SPD process rather than w3wp.exe here.

HTH,

Chris.

Anonymous said...

Chris,

Can you get the Content Type name in a ListItemProperty control from the NewForm?

If so, how?

Chris O'Brien said...

@Sam,

Not in a position to try this right now, but have you tried using 'ContentType' as the value of the Property attribute? This should work as far as I can see, since every SharePoint list has a field defined like this:

<FieldRef Name="ContentType" StaticName="ContentType" DisplayName="Content Type" Type="Text" />

Hope it works for you - let me know.

Cheers,

Chris.

Anonymous said...

Chris,

It looks like you can use ContentType in Edit (and I'm assuming View), but not New. I guess it requires that data be present to query against. It strikes me as odd, though that it is not able to do the lookup against the ContentTypeId that is in the QueryString.

I'll let you know if I come across something else, but I imagine that I'll have to become slightly evil and embed a custom control to do the work.

Chris O'Brien said...

@Sam,

Yes, I bet you're correct that the data needs to be there for a query under the covers.

Good luck with your lateral thinking :-)

C.

Anonymous said...

Great article Chris, just a question, if you want to output a look up list filed value on a page, what control do you use?