Take the 2-minute tour ×
SharePoint Stack Exchange is a question and answer site for SharePoint enthusiasts. It's 100% free, no registration required.

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();
share|improve this question
    
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 done –  MdMazzotti Mar 6 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 Mar 6 at 15:52
    
I think the answer is because...it's Microsoft :) –  MdMazzotti Mar 6 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 ? –  Cameron Verhelst Mar 7 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 details –  Cameron Verhelst Mar 7 at 12:47

5 Answers 5

up vote 3 down vote accepted

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.

share|improve this answer
    
Page can contain many listviewwebparts. How would you find the view you created? –  thomius Mar 30 at 7:39
    
Added the logic of finding the id in the end of the question –  thomius Mar 30 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 Mar 30 at 19:21
    
Oh, that's great solution. –  Vadim Gremyachev Mar 30 at 19:57

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.

share|improve this answer
    
Also didn't get it working via web services (msdn.microsoft.com/en-us/library/office/…) –  thomius Mar 13 at 23:26
    
I have posted a feature request on UserVoice under CSOM Gaps category about. Also linking this discussion ( officespdev.uservoice.com/forums/224641-general/suggestions/… ) –  Massimo Prota Aug 28 at 16:27

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;
 }
share|improve this answer
    
Did you try this with document libraries? They don't seem to use the default view. –  thomius Mar 10 at 7:32
    
@thomius, you are right, unfortunately the specified workaround works only for list, but not for libraries –  Vadim Gremyachev Mar 10 at 14:55
    
So I would remove this answer, as it doesn't really provide a solution to the OP's question –  MdMazzotti Mar 11 at 0:08

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; }
    }
}
share|improve this answer
    
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? –  Phil Greer Jul 4 at 15:24

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.

share|improve this answer
    
This solution is for Server Side Object Model (SSOM). Question is about doing it in CSOM (Client Side Object Model). –  W0ut Aug 22 at 8:20

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.