Saturday, June 4, 2011

Problem with updating current navigation settings via object model in Sharepoint

Recently I faced with interesting problem. There are a lot of publishing sites in the intranet and we needed to update current navigation settings on all sites with “Display the same navigation items as the parent site” option:


I created a small tool which updates current navigation on all sites:

   1: class Program
   2: {
   3:     static void Main(string[] args)
   4:     {
   5:         if (args.Length != 1)
   6:         {
   7:             Console.WriteLine("Usage: UpdateNavigation.exe <site_url>");
   8:             return;
   9:         }
  11:         Console.WriteLine("Start");
  12:         using (var site = new SPSite(args[0]))
  13:         {
  14:             using (var web = site.OpenWeb())
  15:             {
  16:                 foreach (SPWeb subweb in web.Webs)
  17:                 {
  18:                     walk(subweb);
  19:                 }
  20:             }
  21:         }
  22:         Console.WriteLine("Finish");
  23:     }
  25:     private static void walk(SPWeb web)
  26:     {
  27:         if (web == null)
  28:         {
  29:             return;
  30:         }
  32:         Console.WriteLine("Check web '{0}'", web.Url);
  33:         var pweb = PublishingWeb.GetPublishingWeb(web);
  34:         if (!pweb.Navigation.InheritCurrent)
  35:         {
  36:             Console.WriteLine("\tInherit current navigation for '{0}'", web.Url);
  37:             pweb.Navigation.InheritCurrent = true;
  38:             pweb.Web.Update();
  39:         }
  41:         foreach (SPWeb subweb in web.Webs)
  42:         {
  43:             walk(subweb);
  44:         }
  45:     }
  46: }

As you can see it is pretty simple: it goes through all sites recursively and updates the navigation settings. The tool successfully updated all sites and left navigation became inherited from parent sites on all sub sites. However on some sub sites (not on all of them) in Site Settings > Navigation option “Display the current site, the navigation items below the current site, and the current site's siblings” was shown:


The strange thing was that as I said left navigation correctly showed the navigation items from the parent site on all sites. Moreover PublishingWeb.Navigation.InheritCurrent was set to true, because these sites were not updated when I ran the tool second time.

I checked the logic of the code behind class of the AreaNavigationSettings.aspx page (Microsoft.SharePoint.Publishing.Internal.CodeBehind.AreaNavigationSettingsPage). It has the following controls of HtmlInputRadioButton type for each option for the current navigation settings:

Control ID Title
inheritLeftNavRadioButton Display the same navigation items as the parent site
showSiblingsLeftNavRadioButton Display the current site, the navigation items below the current site, and the current site's siblings
uniqueLeftNavRadioButton Display only the navigation items below the current site

That’s how it uses these controls:

   1: protected override void OnLoad(EventArgs e)
   2: {
   3:     ...
   4:     this.inheritLeftNavRadioButton.Checked =
   5:         base.CurrentPublishingWeb.Navigation.InheritCurrent;
   6:     this.showSiblingsLeftNavRadioButton.Checked =
   7:         base.CurrentPublishingWeb.Navigation.ShowSiblings;
   8:     this.uniqueLeftNavRadioButton.Checked =
   9:         !base.CurrentPublishingWeb.Navigation.InheritCurrent && !this.showSiblingsLeftNavRadioButton.Checked;
  10:     ...
  11: }
  13: protected void OKButton_Click(object sender, EventArgs e)
  14: {
  15:     ...
  16:     publishingWeb.Navigation.InheritCurrent =
  17:         this.inheritLeftNavRadioButton.Checked;
  18:     publishingWeb.Navigation.ShowSiblings =
  19:         this.showSiblingsLeftNavRadioButton.Checked;
  20:     ...
  21:     publishingWeb.Web.Update();
  22:     base.RedirectToFinishUrl();
  23: }

As you can see even if these 3 controls belong to the same group, via project model it is possible to specify both properties PublishingWeb.Navigation.InheritCurrent and PublishingWeb.Navigation.ShowSiblings to true. Via UI it is not possible. And in such situation Sharepoint will show “Display the current site, the navigation items below the current site, and the current site's siblings” because appropriate control (showSiblingsLeftNavRadioButton) is initialized after control with “Display the same navigation items as the parent site” title (inheritLeftNavRadioButton). This is error-prone implementation because if before displaying the AreaNavigationSettings.aspx page both properties were set to true, user didn’t changed anything and clicked Ok – after it PublishingWeb.Navigation.InheritCurrent will set to false and PublishingWeb.Navigation.ShowSiblings will remain true (as I said above according to the logic of the code behind these properties can not be set to true simultaneously via UI).

So I just add the one line of code in order to fix my tool and after that navigation settings for all sites showed correct value (“Display the same navigation items as the parent site”):

   1: var pweb = PublishingWeb.GetPublishingWeb(web);
   2: pweb.Navigation.InheritCurrent = true;
   3: pweb.Navigation.ShowSiblings = false;
   4: pweb.Web.Update();

Keep it in mind when you will modify navigation settings via object model.

No comments:

Post a Comment