Wednesday, May 28, 2008

OFC15-ILL - ASP.NET 2.0 Interoperability with Windows SharePoint Services 3.0: Web Parts

I will be presenting this topic twice at TechEd 2008 in Orlando. The first presentation will be Wednesday June 4 @ 9:45 AM. The second will be Thursday, June 5 @ 2:15 PM.

The slide deck, lab, and lesson plan are now available here.

HOL302: ASP.NET 2.0 Interoperability with Microsoft ® Windows® SharePoint® Services 3.0 - Web Parts

Learn about the Microsoft Windows SharePoint Services 3.0 Web Part framework, designed and built on the Microsoft ASP.NET 2.0 Web Part infrastructure. The Windows SharePoint Services 3.0 Web Part framework uses many controls in the ASP.NET 2.0 Web Part control set, and introduces several of its own that inherit from base classes supplied by the ASP.NET 2.0 Web Part control set.

Monday, May 26, 2008

Custom Navigation for WSS

The navigation in WSS 3.0 has been limited. The majority of the features have been limited to MOSS 2007 due to navigation being ties to publishing. WSS gives us just enough to customize the top navigation in one layer. All though MOSS only provides two layer functionality OOB, we can acheive custom navigation in both platforms. In this article, I will cover how to add a multi-layer navigation object to WSS using lists inside SharePoint. We will be creating the menu in 4 steps. First we will create the two lists in SharePoint followed by the SiteMapProvider in Visual Studio. Then we will make changes to the web config to allow the SiteMapProvider to be used in the master page. We will then alter the menu object in the master page to use the new menu.
First we need to create two lists in SharePoint. The list names I used were “WSSTopNavigation” and “WSSDropDownNavigation”

The structure of WSSTopNavigation looks like the following:






WSSDropDownNavigation is very similar with the execption of it looks up a category from WSSTopNavigation as its link.




The SiteMapProvider can be the tricky part. Create a new project in Visual Studio. The first step is to create a project with a strong name key file and the references diagramed below:



Now create a class file named MenuProvider.cs. The following using statement will be helpful along the way.

using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;
using System.Collections;
using Microsoft.SharePoint.Navigation;

The class will inherit from the SPNavigationProvider. This will allow us to simply the process quite a bit.
The first thing we want to do is override the GetChildNodes. I only wanted to modify the “Home” node for my solution. One thing to note is that the current nodes created by SharePoint are SPSiteMapNodes. This is internal and presents a small problem. Our new node is of the SiteMapNode. You will need to trap an type error when the GetChildNodes method executes against your new nodes. I trapped this below and returned null.
-------------------------------------------------------------------------------

public override SiteMapNodeCollection GetChildNodes(SiteMapNode node)
{

SiteMapNodeCollection nodeCollection;
try
{

nodeCollection = base.GetChildNodes(node);

if (node.Title == "Home")
{
SiteMapNodeCollection newNodes = GetNodesFromSharePointList(node);
nodeCollection = newNodes;
}
}
catch
{
nodeCollection = null;
}

return nodeCollection;

}
-------------------------------------------------------------------------------

Now all that is needed to complete the class file is to write the GetNodesFromSharePointList method. All I am doing here is building out a SiteMapNodeCollection from the two lists we created in the first step and use CAML to pull them out in position order and to tie the sub-menus to the parents.

-------------------------------------------------------------------------------
private SiteMapNodeCollection GetNodesFromSharePointList(SiteMapNode node)
{
SiteMapNodeCollection wssListNode;
try
{
wssListNode = base.GetChildNodes(node);
}
catch
{
wssListNode = new SiteMapNodeCollection();
}

SPWeb currentWeb = SPContext.Current.Web;
string listName = "WSSTopNavigation";
string secondName = "WSSDropDownNavigation";


if (listName != null && listName.Length > 0)
{
try
{
//Title Single line of text
//Category Single line of text
//Position Number
//NavigationURL Single line of text
//DisplayName Single line of text
//Created By Person or Group
//Modified By Person or Group

SPListItemCollection categoryItems;
SPList categoryList = currentWeb.Lists[listName];
SPList secondList = currentWeb.Lists[secondName];
SPQuery posQuery = new SPQuery();
posQuery.Query = "";
categoryItems = categoryList.GetItems(posQuery);

for (int i = 0; i < nodeurl =" categoryItems[i][" nodetitle =" categoryItems[i][" nodedescr =" categoryItems[i][" secquery =" new" query =" string.Format(">{0}", categoryItems[i]["Category"].ToString());
secItems = secondList.GetItems(secQuery);
SiteMapNode newNode = new SiteMapNode(node.Provider, "/", nodeUrl, nodeTitle, nodeDescr);
newNode.ChildNodes = new SiteMapNodeCollection();

for (int ii = 0; ii < nodesecurl =" secItems[ii][" nodesectitle =" secItems[ii][" nodesecdescr =" secItems[ii][" secnode =" new">
-------------------------------------------------------------------------------

You can now compile your code and either GAC (global assembly cache) your DLL or stick it in the Bin file of your web application.
Now open up the web.config file in the web application folder. Find the SiteMap section and add your new provider.





This bring us to our final step. You have to change the SiteMapProvider in your master page. It should look like the following:



Now do an IISReset and bring up your new page.



Get the source code here.

Friday, May 9, 2008

Remove Incoming Links from the Wiki Tool Bar

You can customize the tool bars that appear in your SharePoint site. In this post we will look at the Incoming Links hyperlink that appears on the Wiki Edit bar.



The file that controls this display is the DefaultTemplates.ascx control. It is located in the ControlTemplates folder. The full path is 'C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\CONTROLTEMPLATES'.

Open this file in either Visual Studio or notepad. I don't recommend using SharePoint Designer as you will most likely mess up the file when you save it.

After you open the file, locate the WikiMiniConsole. You should now be able to see the WikiIncomingLinkButton. Here all that is needed is to add a visible attribute and set it to false. (visible = "false")




Now do an IISRESET and review your page.

Thursday, May 8, 2008

Migrate Your Wiki To Production

So you have spent a great deal of time implementing a Wiki site in your WSS development environment and now you want to migrate it to production. Where do you start?

You might think to create a site template but you will find that when you go to create your new site you will get an error. So here is your work around.

Go to your Wiki (or any other list) and click 'Settings' --> Document Library Settings


Under Permissions and Management click Save document library as template

Click ‘list template gallery’.

Click the List Template Name (WikiWiki) and save it to a location accessible to your new site collection.





Go to the ‘List Template Gallery’ of the Site you need to move your list to. Remember that this needs to be the top site. You will be able to add the list anywhere you want within the structure.

Create a new Wiki Site as you would normally using the ‘Create Site’ functionality.

Now click Site Actions, Site Settings, Site Libraries and Lists

Delete Wiki Pages (Click Customize ‘Wiki Pages’ --> Delete This Document Library )

Under Site Libraries and Lists click Create New Content. You should find your original list name (WikiWiki) under the Lbraries column. Select the original data and name it ‘Wiki Pages’ (or anything else you like).

You have just migrated your Wiki data.

Wednesday, May 7, 2008

Reformat Your Wiki With A SPItemEventReceiver

I was recently asked to develop a solution for reformatting the data in a Wiki. The client added several columns to the wiki to help maintain a standard format. The content in each of the columns were then reformatted and then placed into the ‘wikiField’ column that was to be displayed on the custom master page.
I decided that the best way to handle this new functionality was to create a ‘WikiFormat’ feature. So how do you create such a feature? Well it happens in 5 stages.

1. Setup
2. Code the feature.xml
3. Code the SPWikiFormatFeatureReceiver
4. Code the SPWikiFormatEventReceiver
5. Deploy your new feature

Step 1
First, we will open up Visual Studio and create a C# class project. You will need to add a Project Reference to Microsoft.SharePoint.
This next step isn’t required but helps me with deployment later on. Create a ‘Template’ folder and directly under it create a ‘Features’ folder. Next create one more folder. This will be the name of your feature. I called mine WikiFormat. We want to create an XML file in the final folder and name it feature.xml.
For completeness, add two C# classes at the root level. One will be your FeatureReceiver (SPWikiFormatFeatureReceiver) and the other will be your Event Receiver (SPWikiFormatEventReceiver). When you are done, your project structure should look something like the diagram below:



You will also need to sign your assembly with a key since we will be deploying the final .DLL to the Global Assembly Cache (GAC).
Step 2

Title="WIKIFormat"
Description="Formats contents of columns into Wiki Content"
Version="1.0.0.0"
Scope="Web"
Hidden="FALSE"
DefaultResourceFile="core"
ReceiverAssembly="SWB.SharePoint, Version=1.0.0.0, Culture=neutral, PublicKeyToken=d44f145d86ae4ad3"
ReceiverClass="SWB.SharePoint.SPWikiFormatFeatureReceiver"
xmlns="http://schemas.microsoft.com/sharepoint/">


Step 3
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.SharePoint;

namespace SWB.SharePoint
{
class SPWikiFormatFeatureReceiver : SPFeatureReceiver
{
public override void FeatureActivated(SPFeatureReceiverProperties properties)
{
SPSite site = SPContext.Current.Site;
SPWeb web = site.OpenWeb("/wiki-test/");
//SPList wikiSite = web.Lists["Wiki_x0020_Pages"];
string pathURL = "/wiki-test/Wiki%20Pages";

SPList wikiSite = web.GetList(pathURL);
string className = "SWB.SharePoint.SPWikiFormatEventReceiver";
string assemblyName = "SWB.SharePoint, Version=1.0.0.0, Culture=neutral, PublicKeyToken=d44f145d86ae4ad3";

wikiSite.EventReceivers.Add(SPEventReceiverType.ItemAdding, assemblyName, className);
wikiSite.EventReceivers.Add(SPEventReceiverType.ItemAdded, assemblyName, className);
wikiSite.EventReceivers.Add(SPEventReceiverType.ItemUpdated, assemblyName, className);

web.Dispose();
site.Dispose();

}

public override void FeatureDeactivating(SPFeatureReceiverProperties properties){}
public override void FeatureInstalled(SPFeatureReceiverProperties properties) {}
public override void FeatureUninstalling(SPFeatureReceiverProperties properties) {}

}

Step 4


//Please not that the < character has been replaced with a { so format changes would not occur in this blog post.

using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;
using System.Collections;

namespace SWB.SharePoint
{
class SPWikiFormatEventReceiver : SPItemEventReceiver
{
public override void ItemAdding(SPItemEventProperties properties)
{
base.ItemAdding(properties);
}

public override void ItemAdded(SPItemEventProperties properties)
{
base.ItemAdded(properties);
FormatItem(properties);
}

public override void ItemUpdated(SPItemEventProperties properties)
{
base.ItemUpdated(properties);
FormatItem(properties);
}

private void FormatItem(SPItemEventProperties properties)
{
try
{
//Set update flag
bool updateWikiContent = false;

//Stop other event Firing();
this.DisableEventFiring();

//Get the list item from the event properties
SPListItem item = properties.ListItem;

SPView defaultView = item.ParentList.DefaultView;

//Build the Wiki Content
StringBuilder wikiContent = new StringBuilder();

SPViewFieldCollection fields = defaultView.ViewFields;

for (int i = 0; i < fields.Count - 1; i++)
{
try
{
string columnName = fields[i].ToString();
if (columnName != "Edit")
{
columnName = columnName.Replace("_x0020_", " ");
string formatedName = "{h3}" + columnName + "{/h3}{br}";
string inputValue = item[fields[i]] + "{br}";
if (item[fields[i]].ToString().Length > 0)
{
updateWikiContent = true;
wikiContent.Append(formatedName);
wikiContent.Append(inputValue);
}
}
}
catch { }
}

if (updateWikiContent)
{
item["WikiField"] = wikiContent;
}

//Update the list item to apply the new value
item.Update();
}

catch (Exception ex)
{
properties.ErrorMessage = ex.ToString();
properties.Cancel = true;
}

finally
{

//Re-enable event firing
this.EnableEventFiring();
}
}


}

}

Step 5
Now, it is time to deploy. The first thing we will want to do is to move the newly created DLL to the GAC. I prefer the drag and drop method to the GACUTIL but either way works great. Once the DLL is in place, you can copy your folder structure into the 12 hive (C:\Program Files\Common Files\Microsoft Shared\web server extensions\12). If you elected not to use the same file structure I did, you can copy your feature folder (WikiFormat) to C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\FEATURES.
Now we want to install and activate the feature. To install the feature you will need to use the STSADM utility. This is located in the bin folder of the 12 hive.
The syntax is as follows:

Stsadm –o installfeature –name WikiFormat

Once you install the feature, you can activate it one one of several ways. You can use the STSADM tool again using the activeatefeature operation or you can activate the feature at the site level. Don’t forget your IISRest!!!
You are now ready to test your new feature. The code provided reformats the wiki on adds and updates.