Why the out of the Box Content Query Web Part Item Style names friendly and custom styles aren’t


Introduction

 

So firstly this post comes about because I have been working with the Content Query Web Part quite a lot recently and this particular behaviour has been bugging me for ages.

However I have just got back from the European SharePoint Best Practices Conference where Christine Wheeler did some great sessions on the Content Query Web Part and I was hoping to ask her why the following behaviour happens.

However, just before I put my hand up she bet me to it and asked the audience if anyone knew why custom item styles don’t have friendly names and out of the box styles do.

So I thought I really should find out why.

 

Background

So what the heck am I talking about?

Well its this section of the Content Query Web Part that is the problem:-

image

This custom item style “CustomItemStyle” template has an unfriendly name compared to the other out of the box styles.

This screen is reached in the Content Query Web Part by the following:-

  • insert a content query web part on the page
  • Modify its properties
  • Expand the Presentation grouping and you will see two drop-down boxes
  • Group Style and Item Style

image

The “Out of the Box” item styles are displayed as readable descriptive list items.

What commonly happens is that new styles need to be created as none of the out of the box styles give the format that is required. It is possible to create your own style by :-

  • opening SharePoint Designer
  • create a copy of the XSLT style sheet ItemStyle.xslt found in Site Collection Root/Style Library/XSLT Style sheets
  • copy an existing item style template <xsl:template></xsl:template> image
  • give the <xsl:template name attribute a new name and change the match attribute to contain the same text as the name attribute.

Further information can be found in this great post (http://blogs.msdn.com/b/ecm/archive/2006/10/25/configuring-and-customizing-the-content-query-web-part.aspx) on the Microsoft ECM Blog.

When you have added a new style, then you will see the something like below.image

 

There does not seem to be away to control the description and give a friendly name. Looking through the components that make up the Content Query Web Part it would make sense that one of the following style sheets would help:-

  • Header.xslt
  • ItemStyle.xslt
  • ContentQueryMain.xslt

image

I would have expected ContentQueryMain.xslt to have some XSLT that would perform a look up which we could then add to allowing custom friendly ItemStyle descriptions.

 

Investigation

So I started thinking well how does the Content Query Web Part get this information?

The best way to find out is to reflect the code.

The Microsoft.SharePoint.Publishing.dll assembly is where the ContentByQueryWebPart lives so I fired up .NET Reflector and started to disassembly the Microsoft.SharePoint.Publishing.dll

The first place to look was at the class Microsoft.SharePoint.Publishing.WebControls.ContentByQueryToolPart the ToolPart is the control which displays the interface when you modify the web part settings on a SharePoint page.

The control has the following function, populateItemStylesDropDown() this calls back into the parent web part control using function PopulatedItemDropDown passing in the path ~SiteCollection/Style Library/XSL Style Sheets/ItemStyle.xslt.

image

image

The PopulateDropDown is then called with the XSLT Style Sheet link and also the “ItemStyle” string. It is this function where all the item styles are discovered and added to the drop-down list box.

image

If you look at the highlighted section the code tries to resolve a string within a resource file using the Item Style name attribute and prefixing the Item Style name with “ItemStyle”.

If a string is not returned then the template name found in the XSLT is used and hence this is why we see unfriendly style names with custom Content Query Item Styles.

So where are these Item Style names stored?

Well the function Resources.GetString() function is called and the Resources object is also found in the Microsoft.SharePoint.Publishing assembly as Type Microsoft.SharePoint.Publishing.Internal.Resources.

image

The class has a default constructor which defines the details of the resource file to open. It happens that the resources are actually held within the Assembly Microsoft.SharePoint.Publishing.Intl.dll which is found in c:\program files\microsoft office servers\14\bin directory.

image

The Microsoft.SharePoint.Publishing.Intl.dll has embedded resources, one of them being Microsoft.SharePoint.Publishing.Strings.resources, this contains all the Item Style resource strings.

image

image

 

So there you go, that is how the Content Query Web Part displays readable Item style descriptions!

The next question is how do we go about doing our own version of this?

That is something that I haven’t thought about yet. I would be interested in hearing from you on how you would approach this issue.

Unable to create a page based on a Publishing Page Layout


Introduction

This issue reared its head a few weeks ago. One of my clients has a pretty heavily customised Intranet which uses custom site definitions with feature stapling etc.

I have advised them to use separate site collections to help keep their site collections secure but with the main advantage being that they can use separate content databases for each site collection. This is to help ensure that they don’t get large 100Gb databases and issues with SQL Server locking.

Anyway, recently we started seeing an issue where the various contributors to the site (who were not site collection admins) could not create a page using the normal site settings->create page.

They had contribute rights but would get the error message:-

“The list does not exist”

 

Solution

So I started thinking about what the problem could be. The list does not exist message was being displayed before a page has been created and as soon as the user clicked Site Settings->Create a Page.

When you create a page you get a list of page layouts to choose from. So that brought me to checking that the master page gallery was there. I thought maybe someone had deleted the list or a feature had not been activated properly.

The list was there but no permissions were set, ah I thought that will be it.

I added the [Site Name] Members and [Site Name] Owners groups giving the Owners group Contributor permissions and the Members group Reader permissions.

The users could now create page successfully.

The reason that the problem was happening is that as part of the site collection creation process the content managers were being good and cleaning up the unused out of the box publishing SharePoint groups.

These groups include the following:-

  • Approvers
  • Designers
  • Hierarchy Managers
  • Quick Deploy Users
  • Restricted Readers
  • Style Resource Readers

However, this process was removing all the permissions from the master page gallery and hence any users who which were not site collection admins could not access the list.

The next step to this solution is write a Feature Receiver to clean up the SharePoint groups and clean up the permissions, this should help make things easier and ensure that users can start using the site as soon as its setup.

That will have to wait for a further blog post though.

SPListItem.Fields.Contains returns true when you don’t think it should!


Firstly, lets explain the scenario where this isn’t working.

Normally I would use the following code snippet to check that a field exists in an SPListItem object.
SPListItem.Fields.Contains([InternalFieldName])

This usually works really well, except in the following instance. The field is being checked to decide whether a User Interface element should be displayed.

The SPListItem is a content type derived from a Publishing Page Content Type. This content type lives in the /Pages document library along with various other content types.

The user interface element (button) should only display for content types that have a particular field. Unfortunately the button is always displayed as the field check function always return true regardless of the page being displayed.

It took me a while to work this through. Why would a field that is not associated to the page exist? My conclusion was that its because the field existed in the document library, albeit that it was part of another content type.

To workaround this issue, the code was changed from:-

SPContext.Current.ListItem.Fields.ContainsField([InternalFieldName]);

to:-

SPContext.Current.ListItem.ContentType.Fields.ContainsField([InternalFieldName]);

This call now returned false for pages which didn’t have the field associated to their content type. Finally, the user interface element was displayed as it should!

Issues with Custom List Schema and Editing Field Settings (Cannot Perform this Action)


>

Why is it that when you have a deadline looming then you have a problem which takes an age to fix?!

Well I hope that if you have the problem that I had then this post will help you fix it a bit more quickly!

Problem

The problem occurred within a custom list definition which held a lookup field. When the field settings were adjusted, using Settings->List Settings, modifying a field and clicking ok, an error message would be displayed.

“Cannot Perform this Action”

This error message fills me with dread as you have very little information to help you discover the problem.

Some background information, the field was in a custom list created from the custom list feature found in the SharePoint HIVE.

The custom list schema was updated with a unique content type and some additional fields were added. This content type was a list content type which was derived from the Item Content Type and had the ID: 0x0100[GUID]. The content type was stored inside a folder /Folder/Contacts.

Solution

The solution was found by examining other custom list schemas that I have created in the past. The difference was that mine was using a Folder and it didnt have the tag:-

<ContentTypeRef ID=”0x0120″ />

So I added this ContentTypeRef, which is the reference for the Folder content type within the <MetaData><ContentTypes> element at the top of the schema.xml file.

A redeployment of the feature with updated schema.xml updated the schema.xml file in the 12 HIVE and the issue was fixed, fields could now be edited and updated.

I hope this helps save someone a few hours!

Cheers

Simon

Building WSP Solution out of Multiple Visual Studio Projects


>

Introduction
Recently I have been building a reasonable sized SharePoint solution which is using multiple Visual Studio projects. Using the excellent WSPBuilder by Carlos Keutmann, the SharePoint content can be packaged up build individual solution files.
WSP Builder
Ok so as with these things there have been a few hacks to ensure that WSPBuilder does the right thing when building the package. Before I start I should explain how to use WSPBuilder, basically what you do is define the structure of the SharePoint 12 Hive in your project. So you create one folder called 12 and then create sub folders which mimics the SharePoint 12 Hive structure.
So under the 12 folder you would add the appropriate sub folders for your solution :-
TEMPLATESTEMPLATES\LAYOUTS\[YourAppFolder]TEMPLATES\IMAGES\[YourAppFolder]TEMPLATES\FEATURESTEMPLATES\SITETEMPLATES\YOURSITEDEFFOLDER.....
To add assemblies to your solution you create a GAC folder and an 80 folder at the same level as the 12 Folder.
To add an assembly into the GAC put the assembly in the GAC folder. To add an assembly into the web application bin folder put the assembly in the 80 folder.
The Problem
So far so good but when you have multiple projects building multiple assemblies, it is difficult to organise the files so that WSP Builder can build the solution correctly.
This is made worse when you have a project that builds an assembly which is then used by another of the projects.
To explain this if we have two projects, Project A and Project B. Project A builds assembly ProjectA.dll and Project B builds ProjectB.dll, Project B uses Project A.
When Project B is built it relies on the Project A dll and the assembly is copied into Project B’s build directory.
Now if you wanted to package up the solution using WSP Builder, you can run WSP Builder as part of the post build event by running “c:\program files\wspbuilder\wspbuilder.exe”. However if the assemblies, ProjectA.dll and ProjectB.dll need to be in the GAC then we need to build the project and then copy the dlls into the GAC folder.
Thus when the WSP Builder runs it will pickup that the assemlbies need to go into the GAC and build the wsp solution correctly.
These post build events become more and more complex as the number of projects is included in the solution, more complexity equals more room for errors.
A Solution
In order to make things less complex I use the post build events for the projects to copy all the appropriate content from the project directory and build a directory structure under the solution dir.
This can be done as follows:-
echo Running WSP Builderecho Copying GAC Dlls to $(ProjectDir)GACcopy /y "$(TargetDir)*.dll" "$(ProjectDir)GAC\"

echo Copying 12 Directory to Solution Buildxcopy /S /E /I /H /Y "$(ProjectDir)12" "$(SolutionDir)Build\12\"

echo Copying GAC Directory to Solution Buildxcopy /S /E /I /H /Y "$(ProjectDir)GAC" "$(SolutionDir)Build\GAC\"

echo Running WSP Builder against FCT System Solutioncd "$(SolutionDir)Build\%programfiles%\WSPTools\WSPBuilderExtensions\wspbuilder" -WSPName [solutionfilename.wsp]-SolutionId [SolutionIDGUID]

echo Copying packages to Deployment\Packagecopy /y "$(SolutionDir)Build\*.wsp" "$(SolutionDir)Deployment\Package\" copy /y "$(ProjectDir)Package\*.*" "$(SolutionDir)Deployment\Package\":exit
Some enhancements
One of the annoying things when you are coding is that there is a cycle of fix, build, deploy, debug. If you are building the WSP file each time then the cycle between build->deploy->debug can be quite slow. To speed things up I use different build configurations. For example the Debug build does not call the wsp builder command but uses gacutil to add the assembly to the GAC or copies the assembly to the web application bin directory. The application pool is then recycled.
echo Copying content into $(SolutionDir)
copy /y /e /s/i “$(ProjectDir)\12” “$(SolutionDir)\Build\12”
For example:-
This is achieved in the following manner:-
I hope that you find this useful, I would love to hear about other ways that people achieve this and also if anyone has any enhancements to this solution.

Manage Content and Structure (An Unknown Error Occured)


>

Sometimes you have got to love SharePoint, or more importantly love the developers who developed SharePoint to return an exception message such as “An unknown error occured” when something bad happens.

This message occurred when using the Site Actions->Manage Content and Structure feature.

After some investigation a couple of posts on MSDN were found these talked about checking various xml files which customise the Publishing Editing Toolbar and Site Actions toolbar.

The MSDN post said to check that the files were both checked in and published.

However, this did not fix the problem. After further investigation I could see that some lists had two entries in the View All Site Content page (/_layouts/viewlsts.aspx), both which linked to the same list. So the problem is how can we get rid of one of these links?

The first idea was to backup the list as a list template and then delete the list, however this would change the list id when a new list was created from the template.

Instead I had the idea to use the recycle bin feature to bring the list back.

Deleting and restoring the list from the recycle bin did indeed fix the duplicate list links and also fixed the Manage Content and Structure feature!

Next, is to workout why these list entries are duplicated.

Error when creating custom list from New.aspx


>

Introduction

Anyone who’s been developing SharePoint will I am sure have had problems building custom list schemas. However, this one I hadn’t seen before.

The Problem

A custom site definition had been built which activated a feature which created an instance of a custom list for holding event list items.

When the site was created the events list was created perfectly, no problems.

However, when the list is created through the GUI, by clicking on Site Actions->View All Site Content and clicking Create and choosing the custom list type.

This brings up the new.aspx form, once the title and description is filled out and the create button clicked then the following exception was thrown :-

Exception occurred. (Exception from HRESULT: 0x80020009 (DISP_E_EXCEPTION)) at Microsoft.SharePoint.Library.SPRequestInternalClass.CreateListFromFormPost(String bstrUrl, String& pbstrGuid, String& pbstrNextUrl)
at Microsoft.SharePoint.Library.SPRequest.CreateListFromFormPost(String bstrUrl, String& pbstrGuid, String& pbstrNextUrl)

Solution

So the problem is something to do with the list schema.xml file. This schema.xml file is found in the feature directory. I use the following directory structure:-

12HIVE\Templates\Features\ListFeatureName\ListName\schema.xml

Looking at the error, the stack trace mentions the function, CreateListFromFormPost. I thought the issue was due to a custom NewForm page that we were using.

I could not find anything that would fix the issue, even replacing all the custom xml relating to the NewForm element.

However, the schema.xml was missing an attribute, this was the Url=”” attribute part of the <List> element.

This issue was found by comparing the schema.xml file with an out of the box schema.xml. As soon as the Url attribute was provided (even if the attribute was blank) then the list was created properly.

To recap the section of the schema that needed to updated was:-

<List xmlns:ows=”Microsoft SharePoint” Title=”Events” DisableAttachments=”TRUE” FolderCreation=”FALSE” Url=”Lists/Events” EnableContentTypes=”TRUE” BaseType=”0″>

The way that a list is created through a List Feature Instance must be called by some separate code function probably something like CreateListFromListInstanceFeature() instead of CreateListFromFormPost() and hence the list is created ok by the List Feature.

There are a few conversations about this on MSDN but when I first read them I didn’t realise the solution that they were pointing to.

These posts are:-
http://social.msdn.microsoft.com/Forums/en/sharepointcustomization/thread/458e5716-4fa4-425c-9fda-88ce4ccc6203

and

http://social.msdn.microsoft.com/Forums/en-US/sharepointdevelopment/thread/86dd7485-48cc-4836-ad09-40192bd54841

Anyway hope that helps.

Simon