Part 1 - Part 2 - Part 3 - Part 4 - Part 5 - Part 6 - Part 7 - Part 8
So the next part in my series will basically show you how to deploy a Content By Query Web Part (CQWP) and also it's associated elements. The screenshot below shows the structure of my project file now. The Solution package can be downloaded here.
Deploying the Content By Query Web Part
As I mentioned in my previous article, there are various ways of deploying the web part but I feel you have more control by using the API in the code behind rather than using the <Module> element method, there's plenty of links I've collected over on my diigo page. As discussed in my previous web cast, it is important to use the CommonViewFields property to set the Fields that are available in the XSLT.
public override void FeatureActivated(SPFeatureReceiverProperties properties) {
using (SPSite site = new SPSite("http://jt-asuslaptop/"))
{
using (SPWeb web = properties.Feature.Parent as SPWeb)
{
SPFile file = web.GetFile(web.Url + "/default.aspx");
SPLimitedWebPartManager webpartsMng = file.GetLimitedWebPartManager(PersonalizationScope.User);
ContentByQueryWebPart contentByQueryWebPart = new ContentByQueryWebPart();
contentByQueryWebPart.Title = "Schedule";
contentByQueryWebPart.WebUrl = web.Url;
SPListTemplateCollection listTemplates = web.Site.RootWeb.ListTemplates;
SPListTemplate template = listTemplates["Schedule"];
contentByQueryWebPart.BaseType = string.Empty;
contentByQueryWebPart.ServerTemplate = Convert.ToString((int)template.Type, CultureInfo.InvariantCulture);
contentByQueryWebPart.CommonViewFields = "Air_x0020_Date,AirDate;Episode_x0020_Number,Episode;Season_x0020_Number,Season";
contentByQueryWebPart.ItemStyle = "ScheduleStyle";
contentByQueryWebPart.ItemXslLink = site.Url + "/Style%20Library/jeremythake/schedule.xsl";
webpartsMng.AddWebPart(contentByQueryWebPart, "Right", 0);
}
}
}
Cleaning up
Cleaning up after yourself will keep your mum from lecturing you on the finer art of bed making! So with that in mind you should delete the web parts that you've installed on deactivating the feature. All the other stuff is automatically cleaned up such as style sheets etc.
public override void FeatureDeactivating(SPFeatureReceiverProperties properties) {
using (SPWeb web = properties.Feature.Parent as SPWeb)
{
SPFile file = web.GetFile(web.Url + "/default.aspx");
SPLimitedWebPartManager webpartsMng = file.GetLimitedWebPartManager(PersonalizationScope.Shared);
for (int i=0; i< webpartsMng.WebParts.Count; i++)
webpartsMng.DeleteWebPart(webpartsMng.WebParts[i]);
}
}
Writing the style sheet
The style sheet is where all the rendering magic happens. I use the ListAll xsl:template (configured in the ItemStyle property of the ContentByQueryWebPart) to render all the Fields to ensure that I've got the correct property names such as @Episode_x005F_x0020_Number which is not how it was added in CommonViewFields property e.g. Episode_x0020_Number,Episode.
Again, I noticed some formatting issues in the Number and DateTime and found some functions which I've diigo'd.
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet
version="1.0"
exclude-result-prefixes="x d xsl msxsl cmswrt"
xmlns:x="http://www.w3.org/2001/XMLSchema"
xmlns:d="http://schemas.microsoft.com/sharepoint/dsp"
xmlns:cmswrt="http://schemas.microsoft.com/WebParts/v3/Publishing/runtime"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt">
<xsl:template name="ListAll" match="Row[@Style='ListAll']" mode="itemstyle">
<xsl:for-each select="@*">
P:<xsl:value-of select="name()" />
</xsl:for-each>
</xsl:template>
<xsl:template name="ScheduleStyle" match="Row[@Style='ScheduleStyle']" mode="itemstyle">
<h5>
<xsl:value-of select="@Title" />
</h5>
Season: <xsl:value-of select="format-number(@Season_x005F_x0020_Number,'##')" />
- Episode: <xsl:value-of select="format-number(@Episode_x005F_x0020_Number,'##')" />
- Air Date: <xsl:value-of disable-output-escaping="no" select="ddwrt:FormatDate(string(@Air_x005F_x0020_Date), 3081, 1)" />
</xsl:template>
</xsl:stylesheet>
Deploying the style sheet file
Linking to a custom style sheet actually is best practice due to not modifying the ItemStyle.xsl file as this is part of the base install of SharePoint and there is a risk of patches or new versions overriding this. The below code in the Feature Manifest file (elements.xml) allows the deployment of files pointed to in the Path folder attribute to a defined url by the URL attribute. I placed this in the Site Collection scoped feature.
<Module Name="JeremyThakeStyles" RootWebOnly="TRUE" Path="Styles" Url="Style Library/jeremythake">
<File Url="schedule.xsl" IgnoreIfAlreadyExists="TRUE" Type="GhostableInLibrary" />
</Module>
The other neat thing about STSDEV is that you don't have to create .ddf files manually and so adding the .css file into the Visual Studio Project automatically includes it in the Solution .wsp package. You then only have to add an entry into the Feature file itself.
<ElementManifests>
...
<ElementFile Location="Styles\schedule.xsl"/>
</ElementManifests>
"There's one small problem!"
Although this all seems great, the line where I set the ItemXslLink throws an error when it's set...
Unable to display this Web Part. To troubleshoot the problem, open this Web page in a Windows SharePoint Services-compatible HTML editor such as Microsoft Office SharePoint Designer. If the problem persists, contact your Web server administrator.
I've searched for solutions to this and can't seem to find the answer. The XSL path definitely is correct and I can get to "Modify My Web Part" without error. If anyone has any suggestions I'd greatly appreciate it.
"The others"
On my blogging travels I've found some great articles from other awesome SharePoint Experts.
Michael Blumenthal's post on "what do I give to my SharePoint Admin" poses a great question that often comes up from organisations of a size where they have someone who owns the Farm and won't let anyone else near it like a true guard dog! Every farm should be dealt with in this nature and a UAT environment should be in place to ensure that deployments work correctly before doing this in Production. The methods Michael uses are heading more towards Continuous Integration and having a Build server to automatically deploy the packages from source control built projects.
Isahi Sagi also wrote a good article on "planning a SharePoint solution" and point 8 again mentions issues around the fact that not everything can go in the .WSP package, for example InfoPath forms are deployed using stsadm commands. Following on from this, rather than having to type all the stsadm commands in it's better to provide the SharePoint Admin with a script to run to deploy the .wsp package. I'll discuss this in more detail in another post.
Chris O'Briens article has some great samples of Solution Packages. He's doing some great work with SPConfigStore on CodePlex also so check it out. There are lots of approaches to managing configuration per environment. Again, something else I'll be discussing...
Serge van den Oever shined some good light on the Solution Generator for exporting Site definitions and points out some interesting facts about what is exported.
There is also some good presentations from DevConnections too which give a good overview of Solutions.
Waldek Mastykarz also has been busy blogging around this space and seems to be a very good contributor to the MSDN Forums around this too. Waldek makes some great points about big WCM projects where you just simply wouldn't want to script the whole thing as a Feature because it would simply take too long, definitely worth a read on his thoughts on Deployment.
Obviously every man and his dog has blogged about VSeWSS 1.3 so if you hadn't heard about it...you know now ;-)