SharePoint 4 Developers

Additional reference guide in .NET / SharePoint Development

Article published in the .net Magazine

The article shows the reader an introduction to the Web Parts and how to develop Visual Web Parts for SharePoint 2010, showing the development with Visual Studio 2010 and how to take advantage of the features this tool offers.
 capaOnline_net80small

Hi folks,

I would like to inform that in this .net Magazine - issue 80, my exclusive article about WebPart development in SharePoint 2010 was published. Here are more details:

What is this about

The article shows the reader an introduction to the Web Parts and how to develop Visual Web Parts for SharePoint 2010, showing the development with Visual Studio 2010 and how to take advantage of the features this tool offers.

What is it for

One way to customize Web sites and portals in SharePoint is by adding Web Parts. Visual Studio 2010 now becomes a powerful ally in SharePoint 2010 development and brings new templates for development. Visual Web Parts are among these new templates that make the developer's work easier.

In which situation the subject is useful

With the release of SharePoint 2010 lots of .NET developers may begin developing in this platform easily and without trouble, unlike the previous versions that made the arise of new developers difficult. This article brings an approach to .NET developers who want to take advantage of the new features of Visual Studio 2010 to develop SharePoint 2010 solutions.

I think you'll like it! On sale now!

Link to the magazine: http://www.devmedia.com.br/post-18775-Revista--net-Magazine-Edicao-80.html

Cheers,

Marcel Medina

Click here to read the same content in Portuguese.

Customising Form Templates

How to customise Form Templates in SharePoint 2010? The author shows 3 approaches in performing that.

Hi folks,

I have found interesting things in SharePoint Server 2010 after the MOSS 2007 migration project I have worked on recently. Check this out, can you identify the difference between Figures 1 and 2 below?

DocContentType
Figure 1 - Document Content Type

RepContentType
Figure 2 - Report Content Type

It seems obvious isn't it? Save and Cancel buttons are more evident, but the main difference that affects users is the content type choice field.

In the Figures 1 and 2 the content types Document and Report were used. Each one refers to a different Form Template.

Note: For comparative purposes I have excluded the other Report columns not displayed in Figure 2.

What to do if you need to make the Content Type Choice Field available (Figure 1)? I'll show you some approaches to change that.

Approach 1 - SharePoint Manager 2010

This tool is great because it facilitates the work, helping you to the rapid update of SharePoint objects. If you are a SharePointer, you should know it!

When using this tool any update is very simple to be applied, which is displayed in the Figure 3 for the update of the Form Template:

SharePointManager
Figure 3 - Updating the Form Template

The Form Template called RptLibraryForm is responsible for not displaying the content type choice field (Figure 2). As per Figure 3, the solution would be to update the attributes DisplayFormTemplateName, EditFormTemplateName and NewFormTemplateName to another form template, i.e.: DocumentLibraryForm (which is the same as shown in Figure 1).

Form templates are found in content types and they can be changed in two places: the root site collection or document libraries. This type of change would be recommended only for direct change in document libraries, because I do not recommend changing the base object of a root site collection. Any mistake at this level and will affect the site and sub-sites!

When things get complicated a more sustainable solution comes true, which involves the development of form templates.

Approach 2 – Script

A script can be created by using Visual Studio with the creation of a Console Application or via PowerShell.

Regardless of the way it will be executed, the result is the same as the use of SharePoint Manager 2010, but will be done via script.

The code below was developed to run via Console Application:

Code Snippet
  1. static void Main(string[] args)
  2. {
  3.     using (SPSite site = new SPSite("http://portal.sharepoint4developers.net"))
  4.     {
  5.         using (SPWeb web = site.RootWeb)
  6.         {
  7.             // Get the library
  8.             SPDocumentLibrary library = web.Lists["Sample"] as SPDocumentLibrary;
  9.  
  10.             // Change the form template
  11.             library.ContentTypes["Report"].DisplayFormTemplateName = "CustomLibraryForm";
  12.             library.ContentTypes["Report"].EditFormTemplateName = "CustomLibraryForm";
  13.             library.ContentTypes["Report"].NewFormTemplateName = "CustomLibraryForm";
  14.  
  15.             // Update the content type
  16.             library.ContentTypes["Report"].Update();
  17.         }
  18.     }
  19. }

NOTE: The code above is updates a Document Library Content Type.

This is the Powershell script that matches the Console Application:

Powershell
Figure 4 – Powershell script

Download the script here.

Approach 3 - Development of Form Templates

A safe solution is the development of features in SharePoint, because the generated packages can be easily added and activated. Likewise when not in use, disabled and removed.

I recommend sustainable approaches, as they will run smoothly and will not bring you headaches in the future.

Create a new solution in Visual Studio 2010 and name it CustomLibraryFormSolution, as shown in Figure 5:

EmptySolution1
Figure 5 – New Solution

Define the solution as a Farm Solution, validate it and wait for its creation by the Wizard, as per Figure 6:

EmptySolution2
Figure 6 – Wizard

After creating the project a User Control and Feature needs to be created for deployment.

Creating the User Control CustomLibraryForm

This User Control represents a new form template that will be created. To begin add the SharePoint Mapped Folder 14\TEMPLATE\CONTROLTEMPLATES in your project, as displayed in the Figure 7:

MappedFolder1MappedFolder2
Figure 7 – SharePoint Mapped Folder

Note: SharePoint Mapped Folders help a lot. They deploy any file automatically and in the correct place.

Then add a new User Control in this mapped folder and name it CustomLibraryForm, as per Figure 8:

UserControl
Figure 8 – User Control that holds the Form Template

NOTE: If you open the folder 14\TEMPLATE\CONTROLTEMPLATES you can see that it contains several User Controls. The main form templates in use are concentrated in the file DefaultTemplates.ascx.

Delete the files .cs and leave only the .ascx available. Open the User Control, delete all the content and add the code below:

Code Snippet
  1.    <%@ Control Language="C#"AutoEventWireup="false" %>
  2. <%@Assembly Name="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
  3. <%@Register TagPrefix="SharePoint" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" namespace="Microsoft.SharePoint.WebControls"%>
  4. <%@Register TagPrefix="ApplicationPages" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" namespace="Microsoft.SharePoint.ApplicationPages.WebControls"%>
  5. <%@Register TagPrefix="SPHttpUtility" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" namespace="Microsoft.SharePoint.Utilities"%>
  6. <%@ Register TagPrefix="wssuc" TagName="ToolBar" src="~/_controltemplates/ToolBar.ascx" %>
  7. <%@ Register TagPrefix="wssuc" TagName="ToolBarButton" src="~/_controltemplates/ToolBarButton.ascx" %>
  8.  
  9. <SharePoint:RenderingTemplate id="CustomLibraryFormCore" runat="server">
  10.     <Template>
  11.             <table class="ms-formtable" style="margin-top: 8px;" border="0" cellpadding="0" id="formTbl" cellspacing="0" width="100%">
  12.             <SharePoint:ChangeContentType runat="server"/>
  13.             <SharePoint:DocumentLibraryFields runat="server"/>
  14.             <SharePoint:ApprovalStatus runat="server"/>
  15.             </table>
  16.             <SharePoint:WebPartPageMaintenanceMessage runat="server"/>
  17.             <SharePoint:DocumentTransformersInfo runat="server"/>
  18.             <table cellpadding="0" cellspacing="0" width="100%"><tr><td class="ms-formline"><img src="/_layouts/images/blank.gif" width='1' height='1' alt="" /></td></tr></table>
  19.             <table cellpadding="0" cellspacing="0" width="100%" style="padding-top: 7px"><tr><td width="100%">
  20.             <SharePoint:ItemHiddenVersion runat="server"/>
  21.             <SharePoint:InitContentType runat="server"/>
  22.             <wssuc:ToolBar CssClass="ms-formtoolbar" id="toolBarTbl" RightButtonSeparator="&amp;#160;" runat="server">
  23.                 <Template_Buttons>
  24.                     <SharePoint:CreatedModifiedInfo runat="server"/>
  25.                 </Template_Buttons>
  26.                 <Template_RightButtons>
  27.                     <SharePoint:SaveButton runat="server"/>
  28.                     <SharePoint:GoBackButton runat="server"/>
  29.                 </Template_RightButtons>
  30.             </wssuc:ToolBar>
  31.             </td></tr></table>
  32.     </Template>
  33. </SharePoint:RenderingTemplate>
  34.  
  35. <SharePoint:RenderingTemplate id="CustomLibraryForm" runat="server">
  36.     <Template>
  37.             <SharePoint:InformationBar runat="server"/>
  38.             <wssuc:ToolBar CssClass="ms-formtoolbar" id="toolBarTbltop" RightButtonSeparator="&amp;#160;" runat="server">
  39.                 <Template_RightButtons>
  40.                     <SharePoint:SaveButton runat="server"/>
  41.                     <SharePoint:GoBackButton runat="server"/>
  42.                 </Template_RightButtons>
  43.             </wssuc:ToolBar>
  44.             <SharePoint:FormToolBar runat="server"/>
  45.             <SharePoint:FormComponent TemplateName="CustomLibraryFormCore" runat="server"/>
  46.     </Template>
  47. </SharePoint:RenderingTemplate>

NOTE: The code above was extracted from the User Control RptLibTemplate.ascx. Line 12 was the only line added that includes the Content Type Choice field.

Creating the Custom Report Feature

This feature will be responsible for the deployment of a Content Type which uses the new Form Template created. To begin add a new content type and name it CustomReport, as per Figure 9:

Feature2
Figura 9 – New Content Type

The Wizard will appear according to the Figure 10, then select the base content type in which the new content type will inherit from.

wizard1
Figure 10 – Wizard

After its creation the Content Type XML definition is automatically displayed, modify it according to the code below:

Code Snippet
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  3.   <!-- Parent ContentType: Report (0x01010058DDEB47312E4967BFC1576B96E8C3D4) -->
  4.   <ContentType ID="0x01010058DDEB47312E4967BFC1576B96E8C3D4006440fbf80e1849a8bc00166a8703769d"
  5.                Name="Custom Report"
  6.                Group="Business Intelligence"
  7.                Description="References a Custom Form Template"
  8.                Inherits="FALSE"
  9.                Version="0">
  10.     <FieldRefs/>
  11.     <XmlDocuments>
  12.       <XmlDocument NamespaceURI="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms">
  13.         <FormTemplates xmlns="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms">
  14.           <Display>CustomLibraryForm</Display>
  15.           <Edit>CustomLibraryForm</Edit>
  16.           <New>CustomLibraryForm</New>
  17.         </FormTemplates>
  18.       </XmlDocument>
  19.     </XmlDocuments>
  20.   </ContentType>
  21. </Elements>

NOTE: Make sure that the line 8 is changed to Inherits = "FALSE", once it prevents the Form Template informed in the section XMLDocuments to be overwritten by inheritance. Interestingly even setting this attribute to false, the columns are automatically inherited. :)

A feature should be designed to deploy the content type. Add it on the project and set its attributes as shown in Figure 11:

Feature2
Figure 11 – Custom Report Feature Details

Before anything, make sure the checkbox Reset Web Server, which is available at the package properties, is checked. It assures that the User Control is identified immediately after the deployment, check out the Figure 12:

Package
Figure 12 – Package details

NOTE: Download the solution here.

Custom Form Template

In the end, when the form template is created and deployed, according to the Figure 13 check the expected CustomLibraryForm:

CustomRepContentType
Figure 13 – Custom Form Template

NOTE: As you can see, this is the form RptLibraryForm with the addition of the Content Type Choice field.

The three approaches used work very well. As already said, always use best practices and create sustainable solutions.

Unlike the creation of features, scripts are developed faster, although in this case it is a temporary solution. I say this because in the future something can "break" according to the script run (with or without documentation).

I hope it helps.

References:
http://msdn.microsoft.com/en-us/library/aa544142.aspx
http://msdn.microsoft.com/en-us/library/ms468437.aspx
http://msdn.microsoft.com/en-us/library/aa544154.aspx

Cheers

Marcel Medina

Click here to read the same content in Portuguese.

Programmatically Setting Taxonomy Field Values

Setting Taxonomy Field values can be trick, specially because of the lack of documentation. Here I show an example of how to work with the new object model for the migration of field values (Lookup fields X Taxonomy fields).

Hi folks,

This week I have performed the migration of Lookup Lists and Lookup fields. So far I am really impressed by the lack of documentation and examples in how to work with Taxonomy field values.

In this quick note I want to show you guys an example of how to work with the new object model for the migration of field values (Lookup fields X Taxonomy fields).

Assumption

Consider the following Lookup List and Term Store in this example, that contains the World Cup 2010 Brazilian football players, according to Figure 1:

vs680  Figure 1 – Lookup List vs Taxonomy Term Store

Note: As you can see, the decision in migrating Lookup fields to Taxonomy fields is a battle. Does it worth your efforts? In my case as I am creating a Content Type Hub, all the Site Columns must not have dependencies, so a solution is to get rid of Lookup fields.

Lookup fields X Taxonomy fields

Imagine a List that contains both fields, the former maps the Lookup List and the latter the Term Store. In this scenario the Lookup field contains values, on the other hand the Taxonomy field does not, because it was recently created and needs to be filled out.

As a solution for that, the code below maps the Lookup field values into Taxonomy field values, aka Managed Metadata field values.

Code Snippet
  1. static void Main(string[] args)
  2. {
  3.     var url = ConfigurationManager.AppSettings["Url"].ToString();
  4.     var library = ConfigurationManager.AppSettings["Library"].ToString();
  5.  
  6.     // Reads XML, considering
  7.     // (key => lookup field,value => taxonomy field)
  8.     Dictionary<string, string> mappingFields = XMLHelper.ReadDictionaryXML("MappingFields.xml");
  9.  
  10.     using (SPSite site = new SPSite(url))
  11.     {
  12.         using (SPWeb web = site.RootWeb)
  13.         {
  14.             // Gets the list/library
  15.             SPList list = web.Lists[library];
  16.  
  17.             foreach (SPListItem item in list.Items)
  18.             {
  19.                 // Iterates through all mapped fields
  20.                 foreach (var mappedField in mappingFields)
  21.                 {
  22.                     if (item.Fields.ContainsField(mappedField.Key))
  23.                     {
  24.                         // Allows updates without a trace
  25.                         web.Site.AllowUnsafeUpdates = true;
  26.  
  27.                         // Gets the lookup field instance
  28.                         var lookupValueList = (item[mappedField.Key] as SPFieldLookupValueCollection).ToList();
  29.  
  30.                         // Gets the taxonomy field instance
  31.                         TaxonomyField managedField = item[mappedField.Value] as TaxonomyField;
  32.  
  33.                         // Gets the current taxonomy session
  34.                         TaxonomySession session = new TaxonomySession(web.Site, false);
  35.  
  36.                         // Gets the term store (by SspId)
  37.                         var termStoreCol = session.TermStores[managedField.SspId];
  38.  
  39.                         // Gets the terms of a specific term set (by TermSetId)
  40.                         var termCol = termStoreCol.GetTermSet(managedField.TermSetId).Terms;
  41.  
  42.                         var listTerms = new List<Term>();
  43.  
  44.                         // Iterates through the lookup values
  45.                         foreach (var itemValue in lookupValueList)
  46.                         {
  47.                             string value = itemValue.LookupValue;
  48.  
  49.                             // Gets the correspondent term for the each value
  50.                             // found in the lookup values list
  51.                             var termToSet = termCol[value];
  52.  
  53.                             listTerms.Add(termToSet);
  54.                         }
  55.  
  56.                         // Sets the field value using the list of terms
  57.                         managedField.SetFieldValue(item, listTerms);
  58.  
  59.                         // Persists the item
  60.                         item.SystemUpdate();
  61.  
  62.                         // Denies further unsafe updates
  63.                         web.Site.AllowUnsafeUpdates = false;
  64.                     }
  65.                 }
  66.             }
  67.         }
  68.     }
  69. }

Note: The code above is very well commented, so no comments.

I hope it helps.

Reference:
http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.taxonomy.taxonomyfield.aspx

Cheers,

Marcel Medina

Click here to read the same content in Portuguese.