Thursday, August 13, 2009

Changing ListViewWebPart Toolbar and Current View

Recently I came across a situation where I had to change the order of the fields of the current view and change the existing sort order of the current view of Tasks ListViewWebpart. and also my client wanted to change the view so that it shows only ‘Active’ tasks in the webpart. other requirement was to change the toolbar type from ‘Full Toolbar’ to ‘Summary Toolbar’. I know these changes are very easy to do in the UI by going in to edit mode of the ListViewWebPart and editing current view and then selecting the required toolbar type from the drop down box.

Unfortunately, the situation I am in is not so simple. we already have provisioned close to 100 sites and changing all the sites through UI would be a real pain. so, I thought the best way to do this is to write a custom stsadm command that iterates through the site collection which locates the required webpart and then change the toolbar type and edit the current view.

for simplicity, I will not show how to write the stsadm command, but, I will show you how to change the toolbar type and modify the current view of the webpart.

private void ChangeView(List<SPWeb> webs, string targetwp, string list)
{
foreach (SPWeb spWeb in webs)
{
using (spWeb)
{
try
{
using (SPLimitedWebPartManager wm = spWeb.GetLimitedWebPartManager("default.aspx", PersonalizationScope.Shared))
{
SPList spList = spWeb.Lists[list];
ListViewWebPart originalwp = (ListViewWebPart)SPUtil.GetWP(targetwp, wm);
//where query filters all the 'Active' tasks as well as sort on 'Modified'
String wherequery =
"<Where>" +
" <Neq>" +
" <FieldRef Name='Status' />"+
" <Value Type='Choice'>Completed</Value>" +
" </Neq>" +
"</Where>" +
"<OrderBy>" +
" <FieldRef Name='Modified' Ascending='FALSE' />" +
"</OrderBy>";

Guid guid = new Guid(originalwp.ViewGuid);
SPView webPartView = spList.Views[guid];
webPartView.ViewFields.DeleteAll();
webPartView.ViewFields.Add("Title");
webPartView.ViewFields.Add("Assigned To");
webPartView.ViewFields.Add("Due Date");
webPartView.ViewFields.Add("Status");
webPartView.Query = wherequery;
webPartView.RowLimit = 8;
webPartView.Update();
SetToolbarType(webPartView, "Freeform");
originalwp.ViewGuid = webPartView.ID.ToString("B").ToUpper();
wm.SaveChanges(originalwp);
spWeb.Update();
}
}
catch (Exception e)
{
Console.WriteLine(spWeb.Title + " was not processed.reason : " + e.Message);
}
}
}
}

Notice the the line where private method ‘SetToolbarType’ is being called where modifying the toolbar type is happening.

Due to a SharePoint API bug, you can not set the Toolbar type directly. there are plenty of resources out there on how to do this using reflection.

The following piece of code from Mark Stokes blog explains nicely how to change the Toolbar type with reflection.

private static void SetToolbarType(SPView spView, String toolBarType)
{
spView.GetType().InvokeMember("EnsureFullBlownXmlDocument", BindingFlags.NonPublic BindingFlags.Instance BindingFlags.InvokeMethod, null, spView, null, System.Globalization.CultureInfo.CurrentCulture);

PropertyInfo nodeProp = spView.GetType().GetProperty("Node", BindingFlags.NonPublic BindingFlags.Instance);
XmlNode node = nodeProp.GetValue(spView, null) as XmlNode;
XmlNode toolbarNode = node.SelectSingleNode("Toolbar");

if (toolbarNode != null)
{
toolbarNode.Attributes["Type"].Value = toolBarType;

// If the toolbartype is Freeform (i.e. Summary Toolbar) then we need to manually
// add some CAML to get it to work.
if (String.Compare(toolBarType, "Freeform", true, System.Globalization.CultureInfo.InvariantCulture) == 0)
{
string newItemString = "";
XmlAttribute positionNode = toolbarNode.OwnerDocument.CreateAttribute("Position");
positionNode.Value = "After";
toolbarNode.Attributes.Append(positionNode);

switch (spView.ParentList.BaseTemplate)
{
case SPListTemplateType.Announcements:
newItemString = "announcement";
break;
case SPListTemplateType.Events:
newItemString = "event";
break;
case SPListTemplateType.Tasks:
newItemString = "task";
break;
case SPListTemplateType.DiscussionBoard:
newItemString = "discussion";
break;
case SPListTemplateType.Links:
newItemString = "link";
break;
case SPListTemplateType.GenericList:
newItemString = "item";
break;
case SPListTemplateType.DocumentLibrary:
newItemString = "document";
break;
default:
newItemString = "item";
break;
}

if (spView.ParentList.BaseType == SPBaseType.DocumentLibrary)
{
newItemString = "document";
}

// Add the CAML
toolbarNode.InnerXml = @"<IfHasRights><RightsChoices><RightsGroup PermAddListItems=""required"" /></RightsChoices><Then><HTML><![CDATA[ <table width=100% cellpadding=0 cellspacing=0 border=0 > <tr> <td colspan=""2"" class=""ms-partline""><IMG src=""/_layouts/images/blank.gif"" width=1 height=1 alt=""""></td> </tr> <tr> <td class=""ms-addnew"" style=""padding-bottom: 3px""> <img src=""/_layouts/images/rect.gif"" alt=""""><a class=""ms-addnew"" ID=""idAddNewItem"" href=""]]></HTML><URL Cmd=""New"" /><HTML><![CDATA["" ONCLICK=""javascript:NewItem(']]></HTML><URL Cmd=""New"" /><HTML><![CDATA[', true);javascript:return false;"" target=""_self"">]]></HTML><HTML>Add new " + newItemString + @"</HTML><HTML><![CDATA[</a> </td> </tr> <tr><td><IMG src=""/_layouts/images/blank.gif"" width=1 height=5 alt=""""></td></tr> </table>]]></HTML></Then></IfHasRights>";
}

spView.Update();

}
}


That concludes this article on how to change toolbar type and how to modify current view of a list view webpart.

No comments: