Saturday, February 6, 2010

ListViewWebPart & SPView – two sides of the same coin

So, the idea behind this metaphor is that these two SharePoint object model classes are actually two representations of one and the same internal piece of data (or entity). Basically this means that when you create one of the objects you automatically get the other one, when you delete one of them, the other one also gets deleted and when you change the properties of one of them you see visual or other changes in the other. So, list views in SharePoint always come with a pair of representing objects – a ListViewWebPart and SPView – and since behind them is a single entity you can’t have one of the objects in the pair replaced with another SPView or LVWP. In SharePoint 2010 with the introduction of the LVWP inheritor – the XSLT list view web part (XLV) you have the same pairing but with the XLV instead of the LVWP on the web part side.

So, to clarify the above mentioned let me present several examples from the SPView and LVWP perspectives –first, what do we have from the SPView class perspective:

  • When you create a new SPView (from code or the UI alike) you get a web part page (in the list root folder or in the Forms subfolder of the list) containing a LVWP on it that displays the target list’s data. The deleting of the SPView deletes the web part list view page together with the LVWP on it. So far, it sounds rather mundane, doesn’t it?
  • But the more interesting part is when you have the list view web part page and delete the LVWP part on it using the SharePoint UI (you may do that with code too) – the result is that the SPView object that has created the containing web part view page is also deleted – that’s probably something you haven’t expected to happen (be careful to not delete the default view this way). This way you will end up with an empty view (actually ex-view) web part page and no SPView – you can inspect the Views collection property of the containing SPList to make sure that the corresponding SPView is really gone.

And what do we have from the LVWP perspective:

  • When you add a LVWP to a publishing or simple web part page with the UI or code you will get a new SPView in the parent list’s Views collection. The new SPView will have its Hidden property set to true and its DisplayName will be empty. The Guid ID property of the SPView will be the same as the ViewGuid property of the LVWP but also as the ID property itself of the LVWP (save that the ID of the LVWP has the “g_” prefix).
  • When you change the Query property or the ViewFields of this hidden SPView you will see that the changes will become immediately visible in the LVWP. Note that if you have the LVWP on a publishing page that requires check-out you will need to have the page checked out first otherwise you will receive an error when you call the SPView.Update method (I will show a code snippet below how this can be achieved).
  • When you delete the LVWP its hidden SPView also gets deleted. It’s the same the other way around – if you delete the hidden SPView, the LVWP will get deleted (you don’t need to have the page checked out in this case – remember that pretty much the same happens if you delete the SPList itself – then all LVWP based on it get deleted)
  • Another note here – the standard UI for editing the properties of the LVWP is a little bit misleading – you see a drop-down from which you can select one of the existing visible SPViews for the LVWP – you may think that this way you associate the SPView with the LVWP but this is not the case – what happens actually is that the schema of the visible SPView gets copied to the LVWP’s own hidden SPView. You can see that this is the case quite easily – if you modify the visible view that you have “associated” with the LVWP you’ll see that the changes won’t be applied to the LVWP.
  • It’s pretty much the same when you add a LVWP to a page with code: in this case you need to create a new instance of the ListViewWebPart class and set its ListName property and either the ViewGuid or ListViewXml properties. When you set the former, you need to provide the guid ID of an existing SPView – you will notice however that after the LVWP is already added to the page the ViewGuid property now has the ID of its internal SPView not the original one. If you use the ListViewXml you should provide the view schema yourself (to cut a long story short you can use for example the SchemaXml property of the SPView returned by SPList.GetUncustomizedViewByBaseViewId) – then you will have full control over the various parts of the view schema – query, view fields, etc.

So let me now show you several examples of how you can update the LVWP’s hidden SPView with the SharePoint UI and with code and to briefly outline the cases when you may need to do that (just to quickly announce here that there is some good news for SharePoint 2010 about that).

Starting with SharePoint 2007 – from a user interface perspective you can modify the LVWP’s SPView’s schema by getting the web part in edit mode and clicking the “Edit the current view” link in the part’s properties pane – this will open the standard “modify view” application page. Another option here is to select another existing view from the “Selected View” drop-down.

A case in which you don’t have control over certain aspects of the part’s hidden SPView’s schema is when you provision LVWPs with Module features. Basically all you can specify in this case is a “BaseViewID” (which will define the presentation part) but nothing for the view’s query, view fields, etc. So this issue can be resolved only with code – there’re two options here – to either add the LVWPs to the pages with code (manipulating the ListViewXml property) or have the part’s hidden SPView modified after the web parts is already created (with the UI or provisioned with a Module feature). The latter is a little bit tricky, here is a code snippet that can achieve that:

      public void ProcessCommonAction(SPWeb rootWeb, SPWeb web, XElement element)

        {

            string pageUrl = element.Attribute("PageUrl").Value;

            string listUrl = element.Attribute("ListUrl").Value;

 

            SPFile file = web.GetFile(pageUrl);

            if (!file.Exists) return;

 

            Guid listID = file.ParentFolder.ParentListId;

            SPList library = null;

 

            bool inLibrary = !listID.Equals(Guid.Empty);

            if (inLibrary)

            {

                library = web.Lists[listID];

                if (library.ForceCheckout && file.Level != SPFileLevel.Checkout) file.CheckOut();

            }

 

            try

            {

                // it is important that the SPView object is retrieved after the checkout of the file

                SPList listViewList = web.GetList(web.ServerRelativeUrl.TrimEnd('/') + "/" + listUrl);

                SPView view = listViewList.Views.Cast<SPView>().FirstOrDefault(v => v.Url.EndsWith(pageUrl, StringComparison.OrdinalIgnoreCase));

                if (view != null)

                {

                    ViewHelper.AddOrUpdateView(listViewList, view, element.Element(XHelper.WSSNs + "View"));

                }

            }

            finally

            {

                if (inLibrary)

                {

                    if (library.ForceCheckout) file.CheckIn("");

                    if (library.EnableMinorVersions) file.Publish("");

                    if (library.EnableModeration) file.Approve("");

                }

            }

        }

Notice that the page containing the LVWP may need to be checked out before the SPView instance can get updated. Also note that the SPView object should be retrieved only after the page is checked out.

The SharePoint 2010 story

Several pieces of good news here starting with the new XLV web part which comes with numerous improvements over the SharePoint 2007’s LVWP (there is an on-going series on that on the MS SharePoint team blog). One of the main improvements here relevant to this posting is that the presentation settings were moved from the SPView class to the web part itself – the Xsl and XslLink properties of the XLV instead of the cumbersome CAML holding presentation properties in SPView. This means that you can get the query schema copied from existing views with the UI but can provide your custom rendering in the web part itself (remember the problem with free form views in the announcement list in SharePoint 2007).

Another “goodie” in SharePoint 2010 is that you can directly use the standard view editing page (_layouts/ViewEdit.aspx) to modify the XLV’s hidden SPView – you have the button in the ribbon (I like the ribbon already). So you don’t need to do the cumbersome stuff as in SharePoint 2007 – getting the properties pane of the web part opened, etc., but you can just select the XLV (the blue border around the part should appear) so that the “ListTools” tab appears in the ribbon, and then from the “List” sub-tab select “Modify View” – see the image (on a publishing page you will need to have the page checked out otherwise you’ll receive an error when you try to update the view in the view editing page):

xlv1

Notice that the the standard view editing page opens but with the text field for the display name and the check-box for default view hidden (this is a hidden SPView after all), also the delete button is missing, but if you are insistent you can delete the SPView with code (which will of course delete the XLV too):

xlv2

44 comments:

  1. Hi stefan,
    How can i specify the column position/order when i add a new column to an existing list view webpart through code?

    Regards,
    Priya

    ReplyDelete
  2. Hi AnyPriya,
    it's basically with manipulating the ViewFields property of the SPView class: the Add and Delete methods for adding/removing fields; for field reordering I would first use the DeleteAll method and then add the fields in the order that I need to. So you need your changes in this code block:

    if (view != null)
    {
    // modify SPView's properties like ViewFields
    view.Update();
    }

    ReplyDelete
  3. Hi stefan,
    Do you have any idea how to bind data from two different lists(Events list and a custom list) to a single sharepoint calendar control.i.e I have a field called Due date in custom list and eventdate in events list. How do i assign 2 different fields to the startdate property of the calendar control. Am pretty confused. please help me out.

    ReplyDelete
  4. Hi AnuPriya,
    I didn't quite understand what you wanted to achieve and I am not sure if you can get that with the standard Calendar view. So if you start with a lookup field in the Calendar list fetching data from the custom list you will be able to display this field in the calendar view title and sub-heading. Further, if you want to change the "begin date" and "end date" of the calendar view - you can use only Date fields from the Calendar list here. So if you want to use a Date field from the custom list probably the only option is to have a list item receiver in the Calendar list that will update the existing "Start Time" column or a new custom Date column that you may add with a Date value from the related (via the lookup field) item in the custom list.

    ReplyDelete
  5. Hi Stefan,
    I would like to add a field to my custom list which displays an Image, but acts as a hyperlink. In other words like the "Hyperlink or Picture" column, but "Hyperlink AND Picture" instead.
    Is there a way to achieve this without creating CustomField? It must be possible right? Because "Type" field in document library does just that. Thanks in advance.

    ReplyDelete
  6. Hi AnuPriya,
    you can use the standard publishing "Image" field type. here is the schema of the standard PublishingPageImage field:

    <Field ID="{3de94b06-4120-41a5-b907-88773e493458}" Name="PublishingPageImage" StaticName="PublishingPageImage" SourceID="http://schemas.microsoft.com/sharepoint/v3" Group="$Resources:cmscore,group_pagelayoutcolumns;" DisplayName="$Resources:cmscore,column_pageimage_displayname;" Type="Image" Required="FALSE" Sealed="TRUE" RichText="TRUE" RichTextMode="FullHtml"></Field>

    you can put "Image" fields in custom lists too, via custom content types or if you create a custom list template definition or with code (this field type is not available in the SharePoint UI)

    ReplyDelete
  7. Thanks Stefan..I have used the publishing image field type only. But how to achieve image with hyperlink option in a custom list through code/ custom list template defn?

    ReplyDelete
  8. Hi AnuPriya,
    with code you can add an Image field using code like:

    SPList list = web.Lists["list title"];
    list.Fields.AddFieldAsXml(@"<Field ID='{3de94b06-4120-41a5-b907-88773e493458}' Name='PublishingPageImage' StaticName='PublishingPageImage' SourceID='http://schemas.microsoft.com/sharepoint/v3' DisplayName='Publishing Image' Type='Image' Required='FALSE' Sealed='TRUE' RichText='TRUE' RichTextMode='FullHtml'></Field>",
    false, SPAddFieldOptions.AddFieldInternalNameHint);

    if you want to add that field to a custom list definition you can start with a sample list definition like the one here: http://stefan-stanev-sharepoint-blog.blogspot.com/2010/03/sharepoint-2010-listinstance.html and add the Field element used in the code snippet above below the List/MetaData/Fields element (together with the other fields that you will use in the list template).
    you can check more about creating custom list definitions here: http://www.andrewconnell.com/blog/archive/2009/02/08/A-Quicker-Way-to-Create-Custom-SharePoint-List-Templates.aspx

    ReplyDelete
  9. Stefan:

    I'm trying to follow your blueprint to create an XLVWP on the fly, by supplying a ListId and a view XmlDefinition that contains view attributes, ViewFields and a Query. It seems to work as far as creating a hidden view; however, the hidden view seems to be concocted out of the blue -- it's a mobile view that doesn't have any of the ViewField FieldRefs I supplied. Even though I can access this view (after persisting the XLVWP), I can't modify any of the properties of this hidden view.

    Any idea what might be wrong?

    Josh

    (p.s. thanks for a very informative article -- I'd be totally lost without it).

    ReplyDelete
  10. Hi Josh,
    You can use something like this code snippet:

    private static void Test()
    {
    string wUrl = "http://devsp2010-eu1", lUrl = "Lists/Announcements", pageUrl = "default.aspx";

    Action<string, string, Action<SPList>> UseList = (webUrl, listUrl, callBack) =>
    {
    using (SPSite site = new SPSite(webUrl))
    {
    SPWeb web = site.OpenWeb();
    SPList list = web.GetList(web.ServerRelativeUrl.TrimEnd('/') + '/' + listUrl.TrimStart('/'));
    if (callBack != null) callBack(list);
    }
    };

    Guid hiddenViewGuid = Guid.Empty;
    UseList(wUrl, lUrl, list =>
    {
    SPFile file = list.ParentWeb.GetFile(pageUrl);
    SPLimitedWebPartManager mngr = file.GetLimitedWebPartManager(PersonalizationScope.Shared);

    XsltListViewWebPart wp = new XsltListViewWebPart();
    wp.ListName = list.ID.ToString("B").ToUpper();
    wp.ViewGuid = list.DefaultView.ID.ToString("B").ToUpper();
    wp.XmlDefinition = "<View BaseViewID='1'/>";
    mngr.AddWebPart(wp, "Left", 1);

    hiddenViewGuid = new Guid(wp.ViewGuid);
    });

    UseList(wUrl, lUrl, list =>
    {
    SPView view = list.Views[hiddenViewGuid];
    view.ViewFields.Add("Title");
    view.Update();
    });
    }

    ReplyDelete
  11. Note, that the first "UseList" call just adds the XLV web part to the page with default look & feel (using the default view of the list) and the second "UseList" call (you need a fresh version of the SPWeb and SPList instances so that the SPList.Views collection is populated with the newly created hidden SPView) gets the hidden SPView instance which you can modify using the SharePoint object model (add view fields, change the view query, etc.)

    Greets
    Stefan

    ReplyDelete
  12. Stefan, thanks very much (and also for the educational delegate syntax!). I've done some experimenting since last week, and I've gotten most of the technique to work properly -- except for one thing. The API itself doesn't seem to afford any way of creating a FieldRef with Explicit=TRUE in ViewFields.

    Is this something you've seen before, and perhaps overcome?

    Josh

    ReplyDelete
  13. Hi Josh,
    Check this code - http://sites.google.com/site/stefanstanev/sharepoint-samples-1/Program.cs - in the last UseList call you will see how it is possible to replace the full view schema of an existing SPView (in your case the hidden SPView of the XLV). Let me know if this is of help to you.
    Greets
    Stefan

    ReplyDelete
  14. Stefan, I can't get it to work. The closest I get is by getting fresh Site/Web/List objects *plus* checkin/checkout. I can see the new view object, but I can't update it because Sharepoint thinks it's checked out to some other user.

    ReplyDelete
  15. Josh,
    check the full solution with the check out/in:

    Guid hiddenViewGuid = Guid.Empty;
    SPList library = null;
    UseList(wUrl, lUrl, list =>
    {
    SPFile file = list.ParentWeb.GetFile(pageUrl);
    Guid listID = file.ParentFolder.ParentListId;

    if (!listID.Equals(Guid.Empty))
    {
    library = list.ParentWeb.Lists[listID];
    if (library.ForceCheckout && file.Level != SPFileLevel.Checkout) file.CheckOut();
    }

    SPLimitedWebPartManager mngr = file.GetLimitedWebPartManager(PersonalizationScope.Shared);

    XsltListViewWebPart wp = new XsltListViewWebPart();
    wp.ListName = list.ID.ToString("B").ToUpper();
    wp.ViewGuid = list.DefaultView.ID.ToString("B").ToUpper();
    wp.XmlDefinition = "<View BaseViewID='1'/>";
    mngr.AddWebPart(wp, "Left", 1);

    hiddenViewGuid = new Guid(wp.ViewGuid);
    });

    UseList(wUrl, lUrl, list =>
    {
    SPView view = list.Views[hiddenViewGuid];
    //view.ViewFields.Add("Title");
    //view.Update();

    // load the passed viewSchema in an XmlDocument
    XmlDocument doc = new XmlDocument();
    doc.LoadXml(view.HtmlSchemaXml);

    // set the Name attribute with the ID of the hidden LVP's SPView - we use a simple trick to update the full schema of the hidden view
    XmlElement root = doc.DocumentElement;
    root.SetAttribute("Name", view.ID.ToString("B").ToUpper());

    // do some changes to the view schema
    XmlElement viewFieldsEl = doc.SelectSingleNode("//ViewFields") as XmlElement;
    if (viewFieldsEl != null) { viewFieldsEl.InnerXml += "<FieldRef Name=\"Title\" />"; }

    // create a dummy view to hold the new schema
    SPView cloneView = new SPView(list, doc);
    // a small trick with reflection so that we can update the dummy view
    typeof(SPView).GetField("m_bExistsInDatabase", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(cloneView, true);

    // this will actually update the hidden SPView associated with the LVP
    cloneView.Update();


    if (library != null)
    {
    SPFile file = list.ParentWeb.GetFile(pageUrl);

    if (library.ForceCheckout) file.CheckIn("");
    if (library.EnableMinorVersions) file.Publish("");
    if (library.EnableModeration) file.Approve("");
    }
    });

    ReplyDelete
  16. I got it to work (yay!!) by reverting to an earlier solution where I explicitly create the view via SPViewCollection.Add(...). After updating the newly created view, I used your m_bExistsInDatabase fragment to modify it:

    SPView newView = existingViews.Add("Adapted from DataFormWebPart", viewFields, newViewOrderBy, 100, true, false, SPViewCollection.SPViewType.Html, false);
    newView.Hidden = true;
    newView.Scope = SPViewScope.FilesOnly;
    newView.TabularView = false;
    newView.RowLimit = (uint)dfwp.PageSize;
    newView.Toolbar = "Standard";
    newView.Title = "Adapted from DataFormWebPart";
    newView.Update();

    // load the passed viewSchema in an XmlDocument
    XmlDocument doc = new XmlDocument();
    doc.LoadXml(lvwpSchema.ToString());

    // set the Name attribute with the ID of the hidden LVP's SPView - we use a simple trick to update the full schema of the hidden view
    XmlElement root = doc.DocumentElement;
    root.SetAttribute("Name", newView.ID.ToString("B").ToUpper());

    // create a dummy view to hold the new schema
    SPView cloneView = new SPView(web.Lists[dfwp.ListId], doc);
    // a small trick with reflection so that we can update the dummy view
    typeof(SPView).GetField("m_bExistsInDatabase", BindingFlags.Instance | BindingFlags.NonPublic)
    .SetValue(cloneView, true);

    // this will actually update the hidden SPView associated with the LVP
    cloneView.Update();


    It works like a charm!

    Thanks very much for this.
    Josh

    ReplyDelete
    Replies
    1. Josh,

      can you provide me full code to switch to selected-view in webpart in a page?

      thanks,
      Ryan

      Delete
  17. Good to hear all works ;)

    Cheers
    Stefan

    ReplyDelete
  18. I've linked this posting on stackexchange: http://sharepoint.stackexchange.com/questions/20975/how-to-programmatically-set-the-explicit-attribute-of-a-viewfield/22573#22573

    ReplyDelete
  19. Encapsulated as follows:

    private void PersistView (SPView view, SPList list, string viewSchema)
    {
    // Persist the view passed as a parameter
    view.Update();

    // load the passed schema in an XmlDocument
    XmlDocument doc = new XmlDocument();
    doc.LoadXml(viewSchema);

    // Populate the schema with the ID of the view
    XmlElement root = doc.DocumentElement;
    root.SetAttribute("Name", view.ID.ToString("B").ToUpper());

    // create a dummy view to hold the new schema
    SPView cloneView = new SPView(list, doc);

    // trick SharePoint into thinking that the clone view should be persisted
    typeof(SPView).GetField("m_bExistsInDatabase", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(cloneView, true);

    // this saves the clone view, which in turn updates the passed view.
    cloneView.Update();
    }

    ReplyDelete
  20. Stefan -- for some strange reason, Sharepoint ignores the 'BaseViewID="0"' element in my view definition. Any idea why this might be, and whether or not I can set BaseViewID programmatically?

    Thx, Josh

    ReplyDelete
  21. Hi Josh,
    it looks like it's not possible to change the BaseViewID of the SPView once it's created. Actually I was not able to create an XLV whose hidden SPView has BaseViewID=0 either. I tried specifying: wp.XmlDefinition = "<View BaseViewID='0' />"; - but this didn't work.
    The creation of the web part (and the SPView) goes ultimately to this method: SPRequest.AddWebPartToList(string bstrWebUrl, bool fAllUsers, string bstrID, string bstrWebPartTypeID, string bstrAssembly, string bstrClass, bool fIsIncluded, byte bFrameState, string bstrZoneID, int lPartOrder, int lFlags, int lType, int lBaseViewID, string bstrListId, ref byte[] ppsaAllUsersProperties, ref byte[] ppsaPerUserProperties, string bstrWebPartID, ref string[] ppsaLinks) - the parameter lBaseViewID goes with the value 0 (taken from the internal property BaseXsltListWebPart.AppropriateBaseViewId) but the hidden SPView anyway gets created with BaseViewID=1
    Still, do you have any special reason to change the BaseViewID for the XLV web part.

    ReplyDelete
  22. Stefan, to make a long story short, when I create an XsltListViewWebPart by hand (in SPD), the embedded view is given a BaseViewID=0. But if I create it programmatically, it gets a BaseViewID=1 (as we found out). This XLVWP gets connected to a (very good) 3rd-party filter (FilterZen). The filtering ops don't work at all unless the XLVWP's BaseViewID=0, probably because they too are optimized.

    (FYI, one of the things I tried was this -- when creating the XLVWP, I cast it to its DFWP ancestor, whose BaseViewID is settable, and its BaseViewID to zero, but that didn't work. I also tried calling the internal SPViewCollection.AddView that accepts a BaseViewID - with BaseViewID of zero, but that threw a COM 0x80004005 exception).

    I noticed that AppropriateBaseViewId was used to set the BaseViewId, but I'm not able to see the contents of its local variables (perhaps due to optimization), so I wasn't able to follow all of what it was doing ...

    Josh

    ReplyDelete
  23. Hi Josh,
    The trick with the SPD is actually pretty interesting. The SPD doesn't use the object model directly, instead it uses web services (which use the object model in their turn) and some legacy FrontPage stuff based on ISAPI extensions - if you have heard about calling /_vti_bin/owssvr.dll or /_vti_bin/_vti_aut/author.dll you should have some idea about that. So, more to the practical stuff. In order that you can monitor what happens behind the scene when you do stuff with the SPD you will need the HTTP monitoring utility Fiddler 2 (if you don't have it, just google for it and install it - make sure that it tracks the localhost requests). After you run it, start the SPD and open the page to which you are going to add the XLV. You can monitor all requests that the SPD makes to your SharePoint server (mostly web service calls). The moment of the actual adding of the web part to the page is when you click the "save" button in the SPD's toolbar. Check the calls that the SPD makes after this click. You will see that there will be several calls to /_vti_bin/_vti_aut/author.dll - if you inspect these calls you will see that one of them is an HTTP POST request which basically submits the contents of the whole page (as you see it in "code" mode in the SPD) to the server. It is this call that actually creates the new XLV instance.
    So, the theory is more or less clear, but the thing is whether it is possible to simulate the same call programatically. I think it is, but it will require much more digging into this thing trying to figure out all details - I myself haven't tried it so far. Keep also in mind that there is no official documentation about using the author.dll ISAPI extension.
    Let me know if you will choose to give it a try.

    Greets
    Stefan

    ReplyDelete
  24. Stefan, I've got Fiddler and have used it enough that it's saved my bacon a few times. Thanks for the tip -- I'll give it a try and see what it uncovers. I'll be sure to post anything useful here.

    Josh

    ReplyDelete
  25. Hi Stefan,
    I've problem with SPView, when I used it with Joins the Ribbon becomes Disabled.
    Any idea ?

    Thanks

    ReplyDelete
  26. Hi Pdanan,

    I have played with Joins and I can't remember having issues with that, can you just send me the CAML query that you use, so that I try to reproduce it.

    Greets
    Stefan

    ReplyDelete
  27. It's happen when in WHERE condition I used ProjectedField.
    Here, I used 3 lists clients,cities,and countries. and here's my codes:
    SPList list = web.Lists.TryGetList("clients");
    SPView _view = list.Views["JoinView"];
    XmlDocument camlDocument = new XmlDocument();
    camlDocument.LoadXml(
    @"
    [User]
    ".Replace("[User]", @"sby"));
    _view.Query = camlDocument.InnerXml;
    _view.Joins =
    @"




    ";
    _view.ProjectedFields =
    @"
    ";
    _view.Update();

    Or you can see the detail in my blog: http://edanan.wordpress.com/2012/04/29/spview-and-joins/

    Thanks anyway

    ReplyDelete
  28. Sorry, look like the codes broken when I pasted here.

    You can just get my source here: https://skydrive.live.com/redir.aspx?cid=673259d53d317d94&page=self&resid=673259D53D317D94!114&parid=673259D53D317D94!105&authkey=!AjLPwJCKjIjfLpY&Bpub=SDX.SkyDrive&Bsrc=Share

    And Here's the completed story:
    I created 3 lists: clients, cities, and countries. clients has lookup field named "city" to cities list, and cities list has lookup field named "country" to countries list.
    I want to create clients view that also showing field "areacode" in cities list and "President" in countries list, but only if "President" field value is "sby".

    It works with my source above, but the Ribbon becomes disabled. But if I changed WHERE condition to field that's on clients list itself, the Ribbon becomes normal. So I think the cause is ProjectedField ("President") in Where condition.

    So, maybe You've any idea about that..

    Thanks

    ReplyDelete
  29. Hi pdanan,

    I couldn't reproduce your issue - I created the three lists through the UI with the extra fields, then used some of the code from your blog to set up the Joins and ProjectedFields properties of a new view:

    using (SPSite site = new SPSite(url))
    {
    SPWeb web = site.RootWeb;

    string joins =
    @" <Join Type='LEFT' ListAlias='cities'> <Eq> <FieldRef Name='city' RefType='Id'/> <FieldRef List='cities' Name='ID'/> </Eq> </Join>
    <Join Type='LEFT' ListAlias='countries'> <Eq> <FieldRef List='cities' Name='country' RefType='Id'/> <FieldRef List='countries' Name='Id'/> </Eq> </Join> ";
    string projectedFields =
    @" <Field Name='clientareacode' Type='Lookup' List='cities' ShowField='areacode' />
    <Field Name='clientpresident' Type='Lookup' List='countries' ShowField='President' /> ";

    SPList list = web.Lists["clients"];
    SPView newView = list.DefaultView.Clone("zz", 100, true, false);
    newView.Joins = joins;
    newView.ProjectedFields = projectedFields;
    newView.Update();
    }

    then again from the UI I added the projected fields to the view fields of the view and added the filtering on the President field. The view worked just fine with no problems in the ribbon. But still obviously something is different between my setup and yours. Question - do you use SP1 or not - on the server where I tested the installation is without any service packs or updates.
    One thing that you can check though is the client object model calls in the browser. The enabling/disabling of ribbon buttons/groups is controlled only with JavaScript on the client side. The JS makes use of the client object model which basically makes REST web service calls that can be tracked with a simple HTTP tracking utility like Fiddler. If you are able to get some clue from these calls I think it may be helpful. Let me know if you have some progress with that.

    Greets
    Stefan

    ReplyDelete
    Replies
    1. Hi Stefan,
      I'm sure you missed Query with Where condition using projected field, just like this:

      newView.Query="sby";

      so you can reproduce my issue.
      Thanks

      Delete
    2. I mean this( hope this isn't broken):
      newView.Query = @ " sby ";

      If it's broken here is my full source code : https://skydrive.live.com/redir.aspx?cid=673259d53d317d94&page=self&resid=673259D53D317D94!114&parid=673259D53D317D94!105&authkey=!&Bpub=SDX.SkyDrive&Bsrc=Share

      Thanks

      Delete
    3. Hi pdanan,
      Yes, you were right, I was just about to send you the CAML snippet from the SchemaXml property of my view, when it occurred to me that I need to select an item in the web part to see that the item's contextual commands in the ribbon remain disabled. When I was checking before that, I only paid attention to the "new item" button which always stays enabled no matter whether you have an item selected or not.
      So, as I suggested in my previous reply, I checked what's going on with Fiddler and I saw that when you select an item in the web part, the page makes an Ajax call to this URL:

      /_layouts/inplview.aspx?List={C958AD6D-CB45-4442-98CA-7B03D8384EBD}&View={53522E79-C381-45D7-8292-FC6C099CC5B6}&ViewCount=21&ListViewPageUrl=http://devsp2010-eu1/Lists/clients/AllItems.aspx&IsXslView=TRUE&Cmd=EcbView

      (in your case the GUIDs and the URL parameters will be different). And what I saw was that for a normal view this call returns some HTML with JavaScript embedded in it which obviously gets inserted somewhere in the page or is used in some other manner. But guess what - for the view with the projected field filter this call returned instead only a short error message text:

      One or more field types are not installed properly. Go to the list settings page to delete these fields.

      So, my guess at this point is that it is indeed the projected field that is causing the problem and that it is an internal bug (or feature as it always turns out). If I have more time I will have a look with reflector at the internal implementation of the code behind of this ASPX page from this URL.
      As a possible solution - there is a solution I am convinced about that since it all happens in the browser with JS but as to how complex it would be to intercept all these standard JS calls that SharePoint does I have no clue at this moment (I suppose you've seen the many big new JS files that now come with SP 2010 to give you an idea of the expected complexity).

      Greets
      Stefan

      Delete
    4. Thanks Stefan,
      hope it'll solved soon

      Delete
  30. XmlNode calendarViewType = doc.CreateElement("CalendarViewStyles");

    calendarViewType.InnerXml= viewStyle;

    for (int i = 0; i < spWeb.Lists[listGuid].Views.Count; i++)
    {
    var viewId = spWeb.Lists[listGuid].Views[i];
    if (viewId.Title.CompareTo("Calendar") == 0)
    {
    doc.LoadXml(viewId.SchemaXml);
    doc.ChildNodes[0].AppendChild(calendarViewType);
    doc.LoadXml(doc.ChildNodes[0].OuterXml);
    viewId.Title = "kkjhnj";
    viewId.SetViewXml(doc.InnerXml.ToString());
    viewId.Update();
    }
    }

    i am updating SchemaXml and title but only title get updated. I am doing this in Sharepoint Online so reflection is not allow in sand box solution. So what might be solution??

    ReplyDelete
  31. Hi Anonymous,
    I've seen myself the limitations of the SPView.SetViewXml method - it simply can't set all custom bits of CAML which you want to provide to it for the view schema. I tried your code and saw that it didn't work and I can't think of a work-around which is not using reflection so that it will work in SP online.

    Greets
    Stefan

    ReplyDelete
  32. Hi,

    I have one problem after migration from sharepoint 2007 to 2010.
    When I am creating a new view and setting the Count for a column in Totals section then the count is not displaying but for the existing views the count is getting displayed.

    Thanks..

    ReplyDelete
    Replies
    1. One more thing to add in this.. after creating a new view it is refering to not

      Delete
    2. refering to WebPartPages:ListViewWebPart not WebPartPages:XsltListViewWebPart

      Delete
    3. Hi Anonymous,

      I haven't seen this myself, but have you tried to change the SPWeb.UIVersion property of your site (performing a visual upgrade of the SPWeb)

      Greetings
      Stefan

      Delete
  33. Hi,



    The example codes work only after the page is refreshed or by clicking a button twice.

    Guid hiddenViewGuid = Guid.Empty;
    SPList library = null;
    UseList(wUrl, lUrl, list => ...


    Why is that?

    ReplyDelete
  34. Hi,

    I am trying to edit the display view of the webpart. I tried this using powershell.

    $webpartmanager=$web.GetLimitedWebPartManager($pageUrl,[System.Web.UI.WebControls.WebParts.PersonalizationSc

    ope]::Shared)
    $webpart = New-Object Microsoft.SharePoint.WebPartPages.XsltListViewWebPart
    $webpart.ListId = $list.ID;
    $webpart.ViewGuid = $list.DefaultView.ID.ToString();
    $webpartmanager.AddWebPart($webpart, “Zone 1", 0);

    $wptype = $webpart.GetType()
    $viewProperty = $wptype.GetProperty('ContextView',[Reflection.BindingFlags]'NonPublic,Instance')
    $view = $viewProperty.GetValue($webpart,$null)


    I am getting error at $view = $viewProperty.GetValue($webpart,$null). I am getting valid values in $wptype

    & $viewProperty.

    The error is Exception calling "Getvalue" with "2" argument(s). "Object reference not set to an instance of

    an object"--> system.NullReferenceException: Object reference not set to an instance of an object.
    at Microsoft.sharepoint.WebpartPages.Basexsltlistviewwebpart.Ensureview()
    at Microsoft.sharepoint.WebpartPages.Basexsltlistviewwebpart.get_contextview().


    Can you tell me what is wrong with the code.

    Thanks,

    ReplyDelete
  35. Hi Stefan,

    I'm trying to switch webpart selected-view to Gantt Chart from default.
    I tried the following code but it displays always default view.

    XsltListViewWebPart programwebpart = new XsltListViewWebPart();
    programwebpart.ListName = ProgramRM.ID.ToString("B").ToUpper();
    programwebpart.ViewGuid = ProgramRM.Views["Gantt Chart"].ID.ToString("B").ToUpper();
    wpm.AddWebPart(programwebpart, "Top", 2);

    can you tell me what is wrong with the Code?

    thank,
    Ryan


    ReplyDelete