15

How to add a document library XsltListViewWebPart (or list view web part) on page using CSOM with SP2013 when we do not want to use the in-built view with "Name, Modified, Modified By" fields?

Custom lists get imported correctly via CSOM with this xml, and this also works in import via UI directly, but does not work via CSOM for Document Libraries or Linked Lists for example:

<?xml version="1.0" encoding="utf-8" ?> <webParts> <webPart xmlns="http://schemas.microsoft.com/WebPart/v3"> <metaData> <type name="Microsoft.SharePoint.WebPartPages.XsltListViewWebPart, Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" /> <importErrorMessage>Cannot import this Web Part.</importErrorMessage> </metaData> <data> <properties> <property name="ListUrl" type="string">Lists/MyList</property> <property name="XmlDefinition" type="string">&lt;View Name="{ABCDEFGH-ABCD-ABCD-ABCD-ABCDEFGHIJK}" MobileView="TRUE" Type="HTML" Hidden="TRUE" OrderedView="TRUE" DisplayName="" Url="/sites/site/Pages/default.aspx" Level="255" BaseViewID="1" ContentTypeID="0x" ImageUrl="/_layouts/15/images/links.png?rev=23" &gt;&lt;Query&gt;&lt;OrderBy&gt;&lt;FieldRef Name="Order" Ascending="TRUE"/&gt;&lt;/OrderBy&gt;&lt;/Query&gt;&lt;ViewFields&gt;&lt;FieldRef Name="DocIcon"/&gt;&lt;FieldRef Name="Edit"/&gt;&lt;FieldRef Name="URLwMenu"/&gt;&lt;/ViewFields&gt;&lt;RowLimit Paged="TRUE"&gt;99&lt;/RowLimit&gt;&lt;JSLink&gt;clienttemplates.js&lt;/JSLink&gt;&lt;XslLink Default="TRUE"&gt;main.xsl&lt;/XslLink&gt;&lt;Toolbar Type="Standard"/&gt;&lt;/View&gt;</property> <property name="MissingAssembly" type="string">Cannot import this Web Part.</property> </properties> </data> </webPart> </webParts> 

EDIT / Solution:

As Anthony suggested we should first add the XsltListViewWebPart without specifying the view. Adding the web part will automatically create a hidden view in the list and link the web part to it. Updating this view will also update the web part.

Example solution below.

Web part xml:

<?xml version="1.0" encoding="utf-8" ?> <webParts> <webPart xmlns="http://schemas.microsoft.com/WebPart/v3"> <metaData> <type name="Microsoft.SharePoint.WebPartPages.XsltListViewWebPart, Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" /> <importErrorMessage>Cannot import this Web Part.</importErrorMessage> </metaData> <data> <properties> <property name="ListUrl" type="string">MyLibrary</property> <property name="MissingAssembly" type="string">Cannot import this Web Part.</property> </properties> </data> </webPart> </webParts> 

Code:

WebPart importingWebPart = mgr.ImportWebPart(webPartXml).WebPart; // take webPartXml from above WebPartDefinition wpDefinition = mgr.AddWebPart(importingWebPart, "Top", 1); mgr.Context.Load(wpDefinition, d => d.Id); // Id of the hidden view which gets automatically created mgr.Context.ExecuteQuery(); var viewId = wpDefinition.Id; List list = web.Lists.GetByTitle("MyLibrary"); View view = list.Views.GetById(viewId); view.ViewFields.RemoveAll(); view.ViewFields.Add("Title"); view.ViewQuery = "<Where><Eq><FieldRef Name=\"Title\" /><Value Type=\"Text\">Something Here</Value></Eq></Where>"; view.RowLimit = 10; web.Context.ExecuteQuery(); 
7
  • I don't think this is possible with CSOM. Is using the CSOM a requirement? If you could use the server object model, then this could be doneCommentedMar 6, 2014 at 10:01
  • Requirement would be to not use server-side object model... (but if not doable we would probably add a custom web service which uses server-side XsltListViewWebPart). However, strange that the UI import seems to work fine but CSOM import for the same file doesn't... why Microsoft would expose a different functionality for UI and for CSOM...
    – thomius
    CommentedMar 6, 2014 at 15:52
  • I think the answer is because...it's Microsoft :)CommentedMar 6, 2014 at 19:10
  • @MdMazzotti Why do you think it's not possible through CSOM ? I believe the SPLimitedWebPartManager is exposed in CSOM. Thomius, I failed to grasp the actual question, since you seem to have everything figured out. Is the issue that you configure the webpart's view but it resets to a default one when uploading ?CommentedMar 7, 2014 at 11:58
  • @MdMazzoti, Aha, thx for the explanation. I haven't tested myself yet, but when I used to do this I always specified several other view specific properties and never the XmlDefinition. I will post an answer with more detailsCommentedMar 7, 2014 at 12:47

5 Answers 5

9

I came across this today and found another workaround.

When the web part is added to the page it creates a hidden view on the list it is bound to. You can get the hidden view and make the changes to it directly. This works for announcements, calendars and doc libraries from what I have tested so far.

Example:

 private static void AddWebPart(Web web, LimitedWebPartManager mgr, string xmlSchema, string listName, string zoneName, int zoneId) { WebPartDefinition def = mgr.ImportWebPart(xmlSchema); mgr.AddWebPart(def.WebPart, zoneName, zoneId); mgr.Context.ExecuteQuery(); List list = web.Lists.GetByTitle(listName); web.Context.Load(list.Views); web.Context.ExecuteQuery(); foreach (View v in list.Views) { if (v.Hidden) { FixView(v); } } } private static void FixView(View v) { v.ViewFields.RemoveAll(); v.ViewFields.Add("LinkTitle"); v.ViewFields.Add("Description"); v.ViewFields.Add("Location"); v.ViewQuery = "<Where><Eq><FieldRef Name=\"Title\" /><Value Type=\"Text\">Something Here</Value></Eq></Where>"; v.RowLimit = 4; v.Update(); v.Context.ExecuteQuery(); } 

You could probably read out the view fields from your schema and find a nice way to apply them rather than hard coded like the example.

Unfortunately I have not found away to apply a style to the view (e.g. Newspaper, boxed etc.) which is something I also need.

7
  • Page can contain many listviewwebparts. How would you find the view you created?
    – thomius
    CommentedMar 30, 2014 at 7:39
  • Added the logic of finding the id in the end of the question
    – thomius
    CommentedMar 30, 2014 at 10:53
  • 1
    You could ask another question about adding the style. Based on quick trial seems we only can read it via CSOM from ListViewXml property and updating this ListViewXml seems to revert XsltListViewWebPart to its default (hardcoded) values. (did not find anything similar to server-side SPView.ApplyStyle via CSOM)
    – thomius
    CommentedMar 30, 2014 at 19:21
  • Oh, that's great solution.CommentedMar 30, 2014 at 19:57
  • Great workaround! Works like a charm
    – oftedal
    CommentedApr 14, 2015 at 8:47
5
+50

I tested your code and I can confirm the behavior you described.

There seems to be a bug where, no matter what XmlDefinition you specify, a webpart attached to a document library always ends up showing the default OOB view (Name, Modified, Modified By).

If it were server object model, then it would be possible to cast the webpart to the underlying object of type XsltListViewWebPart and change its ViewGuid property (or viewFields using reflection).

Unfortunately, CSOM doesn't expose the underlying types, so AFAIK there's no workaround to overcome this strange behavior.

2
2

Since XsltListWebPart.ViewGuid and XsltListWebPart.XmlDefinition properties are ignored when adding web part via CSOM it makes it impossible to specify custom view for XsltListWebPart web part.

Solution

Since the default view is used when web part provisioned via CSOM, the proposed solution would be to modify default view during web part provisioning:

  • modify default view properties before adding web part on page
  • add web part on page
  • restore default view original state

Example

 using (var ctx = new ClientContext("http://intranet.contoso.com/")) { var web = ctx.Web; var view = GetDefaultView(web,listTitle); var originalViewFields = view.ViewFields.ToArray(); UpdateViewFields(view,new []{ "LinkTitle","Editor"}); //Add web part on page () AddWebPart(ctx.Web, pageUrl, "TopColumnZone", 1, webPartSchemaXml); //Restore default view UpdateViewFields(view,originalViewFields); } /// <summary> /// Get default view /// </summary> /// <param name="web"></param> /// <param name="listTitle"></param> /// <returns></returns> private static View GetDefaultView(Web web,string listTitle) { var list = web.Lists.GetByTitle(listTitle); var viewQuery = list.Context.LoadQuery(list.Views.Include(v => v.ViewFields, v => v.DefaultView)).Where(v => v.DefaultView); list.Context.ExecuteQuery(); return viewQuery.FirstOrDefault(); } /// <summary> /// Update view fields /// </summary> /// <param name="view"></param> /// <param name="viewFields"></param> private static void UpdateViewFields(View view,string[] viewFields) { view.ViewFields.RemoveAll(); foreach (var viewField in viewFields) { view.ViewFields.Add(viewField); } view.Update(); view.Context.ExecuteQuery(); } public static WebPartDefinition AddWebPart(Web web, string pageUrl, string zoneId, int zoneIndex, string webPartXml) { var file = web.GetFileByServerRelativeUrl(pageUrl); var webPartManager = file.GetLimitedWebPartManager(PersonalizationScope.Shared); var webPartImportedDef = webPartManager.ImportWebPart(webPartXml); var webPartDef = webPartManager.AddWebPart(webPartImportedDef.WebPart, zoneId, zoneIndex); web.Context.Load(webPartDef); web.Context.ExecuteQuery(); return webPartDef; } 
3
  • Did you try this with document libraries? They don't seem to use the default view.
    – thomius
    CommentedMar 10, 2014 at 7:32
  • @thomius, you are right, unfortunately the specified workaround works only for list, but not for librariesCommentedMar 10, 2014 at 14:55
  • So I would remove this answer, as it doesn't really provide a solution to the OP's questionCommentedMar 11, 2014 at 0:08
1

If anyone stumbles upon this. I have done a post on this : ADD DOCUMENT LIBRARY WEBPART IN SHAREPOINT 2013 PAGE

As requested by Phil, I putting all step here too.

Steps:

  1. First add document library in a page and save it.

  2. Open Page and edit it with SharePoint Designer, if you do not have SharePoint Designer, you can download the page on your computer and Find document library webpart markup, and set exportMode=”All” and save it.

  3. Now open page on SharePoint Online and click edit. On Document Library Webpart on right corner, click the icon and you will see export option now. Export the XML and save it. This is XML that you will use to add webpart on a page via CSOM. Note the Field ListID, You need to replace the list ID with new or actual library. If you do not replace you will create same library everywhere when you add this webpart with CSOM.

  4. And here is the code to get List ID for a List (Document Library).

  5. Code to add webpart or App Part on a SharePoint page. This works for both depending upon XML supplied.

[WebMethod]

public void AddWebpartSharepointOnline(string siteURL, string pageUrl,string webPartXml,string Title) { using (ClientContext clientContext = new ClientContext(siteURL)) { SecureString passWord = new SecureString(); foreach (char c in sharepointPass.ToCharArray()) passWord.AppendChar(c); clientContext.Credentials = new SharePointOnlineCredentials(sharepointUser, passWord); Microsoft.SharePoint.Client.File page = clientContext.Web.GetFileByServerRelativeUrl(pageUrl); /* /NucleonSite/SitePages/Home.aspx */ LimitedWebPartManager wpm = page.GetLimitedWebPartManager(PersonalizationScope.Shared); WebPartDefinition wpd = wpm.ImportWebPart(webPartXml); wpd.WebPart.Title = Title; wpm.AddWebPart(wpd.WebPart, “Right”, 1); try { clientContext.ExecuteQuery(); } catch { throw; } } } 
1
  • Please add a short summary of the steps outlined in your blog post. Link-only answers are less useful over time as links tend to break. For example, if you move your blog in the future will you remember to return and update this answer with the new URL?CommentedJul 4, 2014 at 15:24
-1

I made it to work on a Document Library using this blog post's hints.

Basically, you just need to get an instance of your XsltListViewWebPart after adding it, using a new WebPartManager, and then use Reflection to get the internal ContextView property:

GetWebPartManagerForPage(web, "SitePages/default.aspx", manager => { var xvl = (from System.Web.UI.WebControls.WebParts.WebPart wp in manager.WebParts where wp.GetType() == typeof(XsltListViewWebPart) select wp).FirstOrDefault(); PropertyInfo pi = xvl.GetType().GetProperty("ContextView", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); SPView view = (SPView)(pi.GetValue(xvl, null)); SetXsltListViewFields(view); manager.SaveChanges(xvl); }); 

Then to update the view to match your needs (in my case, just to have doc name with link):

public static void SetXsltListViewFields(SPView view) { string viewQuery = "<OrderBy><FieldRef Name=\"ID\" /></OrderBy>"; view.Query = viewQuery; view.ViewFields.DeleteAll(); view.ViewFields.Add("DocIcon"); view.ViewFields.Add("LinkFilename"); view.Paged = true; view.RowLimit = 10; view.DefaultView = true; view.Update(); } 

As part of my provisioning process, it is now working well.

1
  • This solution is for Server Side Object Model (SSOM). Question is about doing it in CSOM (Client Side Object Model).
    – Wout
    CommentedAug 22, 2014 at 8:20

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.