Wednesday, November 16, 2011

How to add web part on SharePoint 2010 Wiki Pages / On Rich Content Programmatically


While working with SharePoint 2010 one of my fried came across a scenario where he needed to modify the home page of team site using a feature. Feature should delete the existing content in out of the box team site’s home page and add new web parts.

Though this sounds very simple in first shot but practically little tricky, that’s what I experienced.
SharePoint 2010 has come up with new features and one of them is modification in team sites. If you observe that when a new out of the box team site is created, there is no default.aspx instead default page is replaced by Home.aspx. Home.aspx is a wiki page and resides in the Site Pages library of team site.
As this is a wiki page so it’s good that this supports direct editing and you can add web parts directly in the rich text area using UI. But when it comes to adding web parts to this page programmatically then problem begins.

Waldek Mastykarz has given excellent workaround to this problem where he has shown how to add a web part in Publishing Page Content of publishing page.  We can use similar technique to add web parts to wiki page as well, only difference is of field name of wiki page.
In the example I have added two list view web parts in Home.aspx page , one reside at left and other one is at right of page. This can be done with simple HTML markup where <td> and <tr> are defined with certain widths.

In my case Ultimate output should be like this HTML
//<div class=\"ms-rtestate-read ms-rte-wpbox\" contentEditable=\"false\">
//  <table id=\"layouts table\" style=\"width:100%\">
//      <tr style=\"vertical-align: top;\">
//          <td style=\"width=66.6%\">
//              <div class=\"ms-rtestate-read {0}\" id=\"div_{0}\"></div>
//          </td>
//          <td style=\"width=33.3%\">
//              <div class=\"ms-rtestate-read {1}\" id=\"div_{1}\"></div>
//          </td>
//      </tr>
//  </table>
//</div>

In example above {0} and {1} would be replaced by GUIDs of web parts.
I have tried this with console application for POC but one can add this in feature receiver.



using (SPSite site = newSPSite("http://yoursite/"))
{
using (SPWeb _web = site.OpenWeb("/yourteamsite"))
   {
SPList _list1 = _web.Lists.TryGetList("List1");
SPList _list2 = _web.Lists.TryGetList("List2");
SPList _sitePages = _web.Lists.TryGetList("Site Pages");

SPFile _file = _web.GetFile(_web.Url + "/SitePages/Home.aspx");

if (_list1 != null&& _list2 != null)
     {
XsltListViewWebPart _list1View = newXsltListViewWebPart();
       _list1View.ListId = _list1.ID;
       _list1View.ViewGuid = _list1.DefaultView.ID.ToString("B").ToUpper();
       _list1View.XmlDefinition = _list1.DefaultView.GetViewXml();

XsltListViewWebPart _list2View = newXsltListViewWebPart();
       _list2View.ListId = _list2.ID;
       _list2View.ViewGuid = _list2.DefaultView.ID.ToString("B").ToUpper();
       _list2View.XmlDefinition = _list2.DefaultView.GetViewXml();

if (_file != null)
       {
using (SPLimitedWebPartManager _mgr = _web.GetLimitedWebPartManager(_file.Url, System.Web.UI.WebControls.WebParts.PersonalizationScope.Shared))
         {
Guid storageKey1 = Guid.NewGuid();
string wpId = String.Format("g_{0}", storageKey1.ToString().Replace('-', '_'));
          _list1View.ID = wpId;

Guid storageKey2 = Guid.NewGuid();
string _liWPID = String.Format("g_{0}", storageKey2.ToString().Replace('-', '_'));
           _list2View.ID = _liWPID;
           _list2View.ID = _liWPID;

//Deleting Web Parts
for (int i = _mgr.WebParts.Count - 1; i > 0; i--)
          {
            _mgr.DeleteWebPart(_mgr.WebParts[i]);
          }

//Adding Web Part
          _mgr.AddWebPart(_list1View, "wpz", 0);
          _mgr.AddWebPart(_list2View, "wpz", 1);

//Deleting Wiki Content
           _file.Item[SPBuiltInFieldId.WikiField] = string.Empty;
 _file.Item.UpdateOverwriteVersion();

string marker = String.Format(CultureInfo.InvariantCulture, "<div class=\"ms-rtestate-read ms-rte-wpbox\" contentEditable=\"false\"><table id=\"layouts table\" style=\"width:100%\"><tr style=\"vertical-align: top;\"><td style=\"width:66.6%\"><div class=\"ms-rtestate-read {0}\" id=\"div_{0}\"></div></td><td style=\"width:33.3%\"><div class=\"ms-rtestate-read {1}\" id=\"div_{1}\"></div></td></tr></table></div>", storageKey1.ToString("D"), _ storageKey2.ToString("D"));


_file.Item[SPBuiltInFieldId.WikiField] = marker;
            _file.Item.UpdateOverwriteVersion();

Console.WriteLine("done");
          }
}

        }

       }
      }

Console.ReadLine();
   }

Working with SharePoint Multilingual Titles Programatically

Last week I was doing some R&D on SharePoint Multilingual user interface and hence thought to share some learning experience which I got.


Background:
SharePoint 2010 ships with the new feature called Multilingual User Interface, which is helpful for displaying the content in the web site in various languages depending upon user selection. I will not dive in to the much details of it as many of good posts are available on the same. Some examples can be found Here and Here.
Just a basic rule of this feature is, it works on the UI culture of the current thread, and shows content to user in different languages.

Problem:
So far so good, SharePoint 2010 manages to translate all link titles, list, libraries titles, site columns titles, content type’s titles and many more things which are out of the box. So when user selects a different language in MUI selector menu then he or she is able to see the OOB translated content very well , but what happens when we have our custom lists, list web parts, custom site columns, content types ? Those don’t get translated by default.

Solution:
One has said very well, there is always a solution J and this line cheers me up. So to overcome this kind of scenario there are two ways.

1.  Manual Approach: one has to go to each and every created custom lists, site columns, and content types and update titles of the same in different languages by changing languages every time using MUI selector. Though this sounds easy but takes lots of efforts when you have sites already provisioned and there is lots of such custom data.

2. Programmatic Approach: I always love such approaches and so I always try to find way to do them as they makes life easy by just few clicks.

A property “TitleResource” is available now with some SharePoint objects which is of type SPUserResourceclass, with which you can get or set the titles of webs, lists, site columns, content types for multiple language cultures.
Following example shows that how we can get or set the multilingual values of a site’s title for German UI culture.



using (SPSite site = newSPSite("http://YourSite"))
{
using (SPWeb _web = site.OpenWeb())
  {
Console.WriteLine(string.Format("{0}-{1}", "Title", _web.Title));

SPUserResource _userResource = _web.TitleResource;
if (_userResource != null)
    {
       _web.AllowUnsafeUpdates = true;
       _userResource.SetValueForUICulture(newSystem.Globalization.CultureInfo(1035), "German Title");
       _userResource.Update();
       _web.AllowUnsafeUpdates = false;

Console.WriteLine("{0}-{1}-{2}", "Updated Title for Culture", "German", _userResource.GetValueForUICulture(newSystem.Globalization.CultureInfo(1035)));

}
  }
}
Console.ReadLine();