Finally Editing a ListViewWebPart View

Finally I was able to edit a newly added ListViewWebPart view by code. I know there is a lot of blogs talking about this topic but I did not find one that is complete with all the bits and pieces so when I managed to do it I decided I have to put the full picture.

 

Adding a new ListViewWebPart is easy you simply add it as follows

using (SPSite site = new SPSite("SOME WEB URL"))
{
using (SPWeb web = site.OpenWeb())
{
SPList list = web.Lists["SOME LIST NAME"];
SPFile NewPage = web.GetFile("default.aspx");
SPLimitedWebPartManager mgr;
mgr = NewPage.GetLimitedWebPartManager(PersonalizationScope.Shared);
ListViewWebPart wp = new ListViewWebPart();
wp.ListId = list.ID;
wp.ViewGuid = list.DefaultView.ID.ToString("B").ToUpper();
mgr.AddWebPart(wp, "Right", 1);
}
}

 

So we choose the list default view as the web part view. So you might be thinking to edit this web part view it is simple right, just edit the default list view before adding it to the web part. WRONG. See how this works is a little different than expected. When you add a new web part and give it any list view GUID the web part actually uses this GUID to get this default view schema from the list definition and then creates a new HIDDEN view based on this schema and adds this new view to the list. So actually if you tries to get the web part view GUID after you added the web part to the page you will find that this web part view GUID is not the GUID you supplied for the web part view during the creation process; Tricky.

So to do this what you need is to get the view of the web part after it has been added then get this view from the associated list and when you edit this view then you are editing the real web part view. Here is how this is done.

using (SPSite site = new SPSite("SOME WEB URL"))
{
using (SPWeb web = site.OpenWeb())
{
SPList list = web.Lists["SOME LIST NAME"];
SPFile NewPage = web.GetFile("default.aspx");
SPLimitedWebPartManager mgr;
mgr = NewPage.GetLimitedWebPartManager(PersonalizationScope.Shared);
ListViewWebPart wp = new ListViewWebPart();
wp.ListId = list.ID;
wp.ViewGuid = list.DefaultView.ID.ToString("B").ToUpper();
// we need this to be able to get this web part without iterating the web parts collection
int wpIndex = mgr.WebParts.Count;
mgr.AddWebPart(wp, "Right", 1);
// Need now to update the list so that it reflect the newly added hidden view
list.Update();
// Get the same list object again
list = web.Lists["SOME LIST NAME"];

// now get the newly added web part using its index
wp = mgr.WebParts[wpIndex] as ListViewWebPart;
Guid guid = new Guid(wp.ViewGuid);
SPView wpView = list.Views[guid];
// Now edit this view for example I am removing fields here
if (wpView.ViewFields.Exists("Attachments")) wpView.ViewFields.Delete("Attachments");
if (wpView.ViewFields.Exists("DocIcon")) wpView.ViewFields.Delete("DocIcon");
if (wpView.ViewFields.Exists("Status")) wpView.ViewFields.Delete("Status");
if (wpView.ViewFields.Exists("Priority")) wpView.ViewFields.Delete("Priority");
if (wpView.ViewFields.Exists("DueDate")) wpView.ViewFields.Delete("DueDate");
if (wpView.ViewFields.Exists("PercentComplete")) wpView.ViewFields.Delete("PercentComplete");
if (wpView.ViewFields.Exists("Predecessors")) wpView.ViewFields.Delete("Predecessors");
// You can also change the toolbar type
System.Reflection.PropertyInfo NodeProp = wpView.GetType().GetProperty("Node", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
XmlNode node = NodeProp.GetValue(wpView, null) as XmlNode;
XmlNode tBarNode = node.SelectSingleNode("Toolbar");
if (tBarNode != null)
{
// The available types are either (Standard, Freeform, or None)
tBarNode.Attributes["Type"].Value = "None";
}
// Now you need to update this view
wpView.Update();
}
}

 

I also found another way to get the web part view using reflections on this post from Mark Stokes but I personally did not try it.

Fairly simple if you get the concept. You might notice also how we were able to change the toolbar type using reflections. There are so many blogs also talks about this. Now this might become tricky at sometimes to change the toolbar type using the above code. In some cases the Node property does not contain the toolbar child element and in this case the above code will not work. To get this to work I used the from this post from Jalil Sear. So the changed code would look as below.

using (SPSite site = new SPSite("SOME WEB URL"))
{
using (SPWeb web = site.OpenWeb())
{
SPList list = web.Lists["SOME LIST NAME"];
SPFile NewPage = web.GetFile("default.aspx");
SPLimitedWebPartManager mgr;
mgr = NewPage.GetLimitedWebPartManager(PersonalizationScope.Shared);
ListViewWebPart wp = new ListViewWebPart();
wp.ListId = list.ID;
wp.ViewGuid = list.DefaultView.ID.ToString("B").ToUpper();
// we need this to be able to get this web part without iterating the web parts collection
int wpIndex = mgr.WebParts.Count;
mgr.AddWebPart(wp, "Right", 1);
// Need now to update the list so that it reflect the newly added hidden view
list.Update();
// Get the same list object again
list = web.Lists["SOME LIST NAME"];

// now get the newly added web part using its index
wp = mgr.WebParts[wpIndex] as ListViewWebPart;
Guid guid = new Guid(wp.ViewGuid);
SPView wpView = list.Views[guid];
// Now edit this view for example I am removing fields here
if (wpView.ViewFields.Exists("Attachments")) wpView.ViewFields.Delete("Attachments");
if (wpView.ViewFields.Exists("DocIcon")) wpView.ViewFields.Delete("DocIcon");
if (wpView.ViewFields.Exists("Status")) wpView.ViewFields.Delete("Status");
if (wpView.ViewFields.Exists("Priority")) wpView.ViewFields.Delete("Priority");
if (wpView.ViewFields.Exists("DueDate")) wpView.ViewFields.Delete("DueDate");
if (wpView.ViewFields.Exists("PercentComplete")) wpView.ViewFields.Delete("PercentComplete");
if (wpView.ViewFields.Exists("Predecessors")) wpView.ViewFields.Delete("Predecessors");
// You can also change the toolbar type
SetToolbarType(wpView, "None", false);
// Now you need to update this view
wpView.Update();
}
}

 

The SetToolbarType function definition is as below:

// This is all Jalil Sear code
public static void SetToolbarType(SPView spView, String toolBarType, bool isUpdateView)
{
spView.GetType().InvokeMember("EnsureFullBlownXmlDocument", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.InvokeMethod, null, spView, null, System.Globalization.CultureInfo.CurrentCulture);

System.Reflection.PropertyInfo nodeProp = spView.GetType().GetProperty("Node", System.Reflection.BindingFlags.NonPublic | System.Reflection.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="""">&nbsp;<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>";
}

if (isUpdateView) spView.Update();

}
}

 

Now an extra note is about working with the famous summery view. This is a type of a special view that has an empty GUID. Many posts said that to select this view you simply set the web part view GUID to an empty string; and this is correct. BUT not in all cases. Because this view is a special view it is not created by default for all lists. Actually if you create a new list this view is not created and does not exist, so if you try to select an empty string GUID the web part will use the default view of the list. This view is created when you add the first ListViewWebpart for this list. To overcome this issue what you need to do is to first set the web part view as usual as an empty string then add it and once added update the list. This would create the summery view for you but it is not yet selected as the web part view. So you get the list again and the web part and then set the web part view GUID as empty string again and finally call the web part manager SaveChanges method for this web part and that should do the trick.

Now how can you edit this web part view? As you noticed in the above code I am getting the view from the list using the view GUID. But this view has an empty GUID. Of course this is not true; no objects can have empty GUIDs on SharePoint. It simply has a hidden GUID. So to edit this summery view what you need is to get the view GUID from the definition XML. The code below shows how to work with the summery view.

using (SPSite site = new SPSite("SOME WEB URL"))
{
using (SPWeb web = site.OpenWeb())
{
SPList list = web.Lists["SOME LIST NAME"];
SPFile NewPage = web.GetFile("default.aspx");
SPLimitedWebPartManager mgr;
mgr = NewPage.GetLimitedWebPartManager(PersonalizationScope.Shared);
ListViewWebPart wp = new ListViewWebPart();
wp.ListId = list.ID;
// Choose the non-existing summery view so that it is created
wp.ViewGuid = string.Empty;//list.DefaultView.ID.ToString("B").ToUpper();
// we need this to be able to get this web part without iterating the web parts collection
int wpIndex = mgr.WebParts.Count;
mgr.AddWebPart(wp, "Right", 1);
// Need now to update the list so that it reflect the newly added hidden view
list.Update();
// Get the same list object again
list = web.Lists["SOME LIST NAME"];

// now get the newly added web part using its index
wp = mgr.WebParts[wpIndex] as ListViewWebPart;
// Now set again the view GUID as empty string after the summery view is created
wp.ViewGuid = string.Empty;
// Save these changes
mgr.SaveChanges(wp);
// Get the view after updates
wp = mgr.WebParts[wpIndex] as ListViewWebPart;
XmlDocument doc = new XmlDocument();
// Load the view definition XML
doc.LoadXml(wp.XmlDefinition);
XmlNode vNode = doc.SelectSingleNode("/View");
// Get the view name attribute (Actually a GUID)
Guid guid = new Guid(vNode.Attributes["Name"].Value);
//Guid guid = new Guid(wp.ViewGuid);
SPView wpView = list.Views[guid];
// Now edit this view for example I am removing fields here
if (wpView.ViewFields.Exists("Attachments")) wpView.ViewFields.Delete("Attachments");
if (wpView.ViewFields.Exists("DocIcon")) wpView.ViewFields.Delete("DocIcon");
if (wpView.ViewFields.Exists("Status")) wpView.ViewFields.Delete("Status");
if (wpView.ViewFields.Exists("Priority")) wpView.ViewFields.Delete("Priority");
if (wpView.ViewFields.Exists("DueDate")) wpView.ViewFields.Delete("DueDate");
if (wpView.ViewFields.Exists("PercentComplete")) wpView.ViewFields.Delete("PercentComplete");
if (wpView.ViewFields.Exists("Predecessors")) wpView.ViewFields.Delete("Predecessors");
// You can also change the toolbar type
SetToolbarType(wpView, "None", false);
// Now you need to update this view
wpView.Update();
}
}


I really hope this shades some light on this very tricky subject and helps.