Blogger

  • This email address is being protected from spambots. You need JavaScript enabled to view it.

    Recent items

Login

Often, the customers asks us to can use the keyword and tags feature into a lists, a document library, etc.

To enable this feature into a list, you may into the list and after from the ribbon, click on List tab, List settings, Enterprise Metadata and Keywords Settings, enable the flag like the picture below.

Now when you are create/edit a new list item, you have the Keyword (and tags) field.

If we need to have this feature already enabled when we deploy and create a custom List, we need to add the settings into the ContentType definition and into the List Definition.

Step 1: First of all, we need to add the the field ref of the fields into the content type

{codecitation}

<ContentType
  ID="0x010100603A64185EFC45C0B8F0274C31CEA0CF"
  Name="KeywordDocument"
  Group="Custom Content Type"
  Description="Custom Content Type with Enterprise Keyword">
 
  <FieldRefs>
    ...
    <FieldRef
      ID="{1390a86a-23da-45f0-8efe-ef36edadfb39}"
      Name="TaxKeywordTaxHTField"
      Hidden="TRUE" />
 
    <FieldRef
      ID="{23f27201-bee3-471e-b2e7-b64fd8b7ca38}"
      Name="TaxKeyword" />
 
    <FieldRef
      ID="{f3b0adf9-c1a2-4b02-920d-943fba4b3611}"
      Name="TaxCatchAll"
      Hidden="TRUE" />

{/codecitation}

Step 2: If you already have the list (and the ListDefinition), you need to add the fields also into the fields tag of the list definition.

{codecitation}

<Fields>

    <Field Type='TaxonomyFieldTypeMulti'
      DisplayName='Enterprise Keywords'
      StaticName='TaxKeyword'
      Name='TaxKeyword'
      ID='{23f27201-bee3-471e-b2e7-b64fd8b7ca38}'
      List="Lists/TaxonomyHiddenList"
      WebId='~sitecollection'
      ShowInViewForms='TRUE'
      DefaultListField='TRUE'
      Required='FALSE'
      Hidden='FALSE'
      ShowField="Term$Resources:core,Language;"
      Mult='TRUE'
      Sortable='FALSE'
      Group="$Resources:osrvcore,field_KeywordsGroupName"
      Description="$Resources:osrvcore,field_KeywordsFieldDesc"
      AllowDeletion='TRUE'>
      <Customization>
        <ArrayOfProperty>
          <Property>
            <Name>SspId</Name>
            <Value
              xmlns:q1='http://www.w3.org/2001/XMLSchema' p4:type='q1:string'
              xmlns:p4='http://www.w3.org/2001/XMLSchema-instance'>00000000-0000-0000-0000-000000000000</Value>
          </Property>
          <Property>
            <Name>GroupId</Name>
          </Property>
          <Property>
            <Name>TermSetId</Name>
            <Value
              xmlns:q2='http://www.w3.org/2001/XMLSchema' p4:type='q2:string'
              xmlns:p4='http://www.w3.org/2001/XMLSchema-instance'>00000000-0000-0000-0000-000000000000</Value>
          </Property>
          <Property>
            <Name>AnchorId</Name>
            <Value
              xmlns:q3='http://www.w3.org/2001/XMLSchema' p4:type='q3:string'
              xmlns:p4='http://www.w3.org/2001/XMLSchema-instance'>00000000-0000-0000-0000-000000000000</Value>
          </Property>
          <Property>
            <Name>UserCreated</Name>
            <Value
              xmlns:q4='http://www.w3.org/2001/XMLSchema' p4:type='q4:boolean'
              xmlns:p4='http://www.w3.org/2001/XMLSchema-instance'>false</Value>
          </Property>
          <Property>
            <Name>Open</Name>
            <Value
              xmlns:q5='http://www.w3.org/2001/XMLSchema' p4:type='q5:boolean'
              xmlns:p4='http://www.w3.org/2001/XMLSchema-instance'>true</Value>
          </Property>
          <Property>
            <Name>TextField</Name>
            <Value
              xmlns:q6='http://www.w3.org/2001/XMLSchema' p4:type='q6:string'
              xmlns:p4='http://www.w3.org/2001/XMLSchema-instance'>{1390a86a-23da-45f0-8efe-ef36edadfb39}</Value>
          </Property>
          <Property>
            <Name>IsPathRendered</Name>
            <Value
              xmlns:q7='http://www.w3.org/2001/XMLSchema' p4:type='q7:boolean'
              xmlns:p4='http://www.w3.org/2001/XMLSchema-instance'>false</Value>
          </Property>
          <Property>
            <Name>IsKeyword</Name>
            <Value
              xmlns:q8='http://www.w3.org/2001/XMLSchema' p4:type='q8:boolean'
              xmlns:p4='http://www.w3.org/2001/XMLSchema-instance'>true</Value>
          </Property>
          <Property>
            <Name>TargetTemplate</Name>
          </Property>
          <Property>
            <Name>CreateValuesInEditForm</Name>
            <Value
              xmlns:q9='http://www.w3.org/2001/XMLSchema' p4:type='q9:boolean'
              xmlns:p4='http://www.w3.org/2001/XMLSchema-instance'>false</Value>
          </Property>
          <Property>
            <Name>FilterAssemblyStrongName</Name>
          </Property>
          <Property>
            <Name>FilterClassName</Name>
          </Property>
          <Property>
            <Name>FilterMethodName</Name>
          </Property>
          <Property>
            <Name>FilterJavascriptProperty</Name>
          </Property>
        </ArrayOfProperty>
      </Customization>
    </Field>
    <Field Type="Note"
      DisplayName="TaxKeywordTaxHTField"
      StaticName="TaxKeywordTaxHTField"
      Name="TaxKeywordTaxHTField"
      ID="{1390a86a-23da-45f0-8efe-ef36edadfb39}"
      ShowInViewForms="FALSE"
      Required="FALSE"
      Hidden="TRUE"
      CanToggleHidden="TRUE" />

    <Field Type="LookupMulti"
      DisplayName="Taxonomy Catch All Column"
      StaticName="TaxCatchAll"
      Name="TaxCatchAll"
      ID="{f3b0adf9-c1a2-4b02-920d-943fba4b3611}"
      ShowInViewForms="FALSE"
      Required="FALSE"
      Hidden="TRUE"
      ShowField="CatchAllData"
      Mult="TRUE"
      List="Lists/TaxonomyHiddenList"
      WebId="~sitecollection"
      Sortable="FALSE"
      AllowDeletion="TRUE"
      Sealed="TRUE" />

</Fields>

{/codecitation}


At this point, we are usually done. The columns were added to the list definition and the columns does indeed show up in the list.

Step 3: The keywords added to items in the list does not show up. What is missing is the event receiver that takes care of the keyword synchronization. Add an Event Receiver to the project. Make sure to select the list you just created as the event source when going through the wizard, and any events in the events list (we will replace the code generated, so it does not matter which).

Step 4: Delete the event receiver's code file (.cs file) so you are only left with the Elements.xml file.

Step 5: Open the event receiver's Elements.xml file and replace whatever <Receiver> tags where generated with these:

{codecitation}

<Receiver>
    <Name>TaxonomyItemSynchronousAddedEventReceiver</Name>
    <Synchronization>Synchronous</Synchronization>
    <Type>ItemAdding</Type>
    <SequenceNumber>10000</SequenceNumber>
    <Assembly>Microsoft.SharePoint.Taxonomy, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c</Assembly>
    <Class>Microsoft.SharePoint.Taxonomy.TaxonomyItemEventReceiver</Class>
    <Data></Data>
</Receiver>
<Receiver>
    <Name>TaxonomyItemUpdatingEventReceiver</Name>
    <Synchronization>Synchronous</Synchronization>
    <Type>ItemUpdating</Type>
    <SequenceNumber>10000</SequenceNumber>
    <Assembly>Microsoft.SharePoint.Taxonomy, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c</Assembly>
    <Class>Microsoft.SharePoint.Taxonomy.TaxonomyItemEventReceiver</Class>
    <Data></Data>
</Receiver>
{/codecitation}

Step 6: The important thing to make sure is that the value of the ListTemplateId attribute on the <Receivers ListTemplateId="xxxxx"> ... </Receivers> tag is the same as the value of the Type="xxxxx" attribute on the < ListTemplate ... /> tag. Otherwise the event receivers will not attach to the right list.

In the next section, I show how you can populate the field code behind (for example, imagine that you have an excel file and use it to populate the list al fill also the Enterprise keyword field).

{codecitation}

internal void LoadReports(string excelPath, SPWeb rootWeb)
        {
            try
            {
                SPList repList = rootWeb.GetList("Lists/Reports");

                ListHelper.ClearList(repList);

                if (repList != null)
                {
                    Console.WriteLine("Lists found!");

                    var wb = new XLWorkbook(excelPath);
                    var ws = wb.Worksheet(2);

                    TaxonomyField tf = repList.Fields.GetFieldByInternalName("TaxKeyword") as TaxonomyField;

                    foreach (IXLTable tb in ws.Tables)
                    {
                        for (int i = 2; i < tb.RowCount() + 1; i++)
                        {
                            IXLRangeRow rw = tb.Row(i);

                            try
                            {
                                string value = string.Empty;

                                SPListItem newItem = repList.AddItem();
                                int j = 0;


                                newItem["Title"] = rw.Cell(j).Value != null ? rw.Cell(j).Value.ToString() : string.Empty;
                                j = 1;
                               
                                newItem["PDFReportURL"] = rw.Cell(j).HasHyperlink ?
                                    repList.ParentWeb.Site.Url + rw.Cell(j).Hyperlink.ExternalAddress.AbsolutePath + (rw.Cell(j).Value != null ? ", " + rw.Cell(j).Value.ToString() : string.Empty)
                                    : string.Empty;

                                j = 2;
                                newItem["Description"] = rw.Cell(j).Value != null ? rw.Cell(j).Value.ToString() : string.Empty;

                                j = 3;
                               
                                TaxonomyFieldValueCollection taxFVC = new TaxonomyFieldValueCollection(tf);
                                value = !string.IsNullOrEmpty(rw.Cell(j).ValueCached) ? rw.Cell(j).ValueCached : string.Empty;
                                string[] values = value.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);

                                List<Guid> itemsToAdd = new List<Guid>();

                                //we need to initialize it every time otherwise we have timeout exception and cannot operate
                                TaxonomySession session = new TaxonomySession(repList.ParentWeb.Site);
                                TermStore termStore = session.TermStores[tf.SspId];
                                TermSet termSet = termStore.GetTermSet(tf.TermSetId);

                                foreach (string a in values)
                                {

                                    string val = a.StartsWith(" ") ? a.Substring(1) : a;

                                    while (val.StartsWith(" "))
                                        val = val.StartsWith(" ") ? val.Substring(1) : val;

                                    Term myTerm = null;

                                    try
                                    {
                                        myTerm = termSet.Terms[val];
                                    }
                                    catch (ArgumentOutOfRangeException)
                                    {
                                        myTerm = termSet.CreateTerm(val, 1033);
                                        termStore.CommitAll();
                                    }

                                    if (myTerm != null && !string.IsNullOrEmpty(myTerm.Name))
                                        itemsToAdd.Add(myTerm.Id);

                                }

                                Guid[] ids = itemsToAdd.ToArray();
                                TermCollection oTerms = session.GetTerms(ids);
                                tf.SetFieldValue(newItem, oTerms);

                                newItem.Update();
                                Logger.WriteLog("Item " + i + "added.");

                            }
                            catch (Exception ex)
                            {
                                Console.WriteLine(string.Format("Error manipulating line {0}.", i));
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.StackTrace);
            }
        }

{/codecitation}

 

Today, during search results test, I found a strange behaviour regards search results. If I did a query with the Administrator user, all results are displayed while when I did a search with others user, the SharePoint Search Corre WebPart returned no search results.

My instructions are supported by KB331951, which states that in order to give accounts read permissions to the tokenGroupsGlobalAndUniversal (TGGAU) attribute you need to add the account to the Windows Authorization Access (WAA) group.

Add an account to the WAA group

Here are the steps you follow to add an account to the WAA group:

  1. Log into the domain controller
  2. Click Start, point to Programs, point to Administrative Tools,
  3. Click Active Directory Users and Computers.
  4. In the Active Directory Users and Computers window, expand DomainName, and then click Users or another appropriate organization unit (OU).
  5. Double-click the SharePoint Services service account you want to modify.
  6. In the Properties dialog box, click the Member Of tab.
  7. On the Member Of tab, click Add.
  8. In the Select Groups dialog box, type Windows Authorization Access Group under Enter the object names to select, and then click OK.
  9. Restart all SharePoint services

Run a Full Crawl the SharePoint Content Source(s)

  1. Browse to Central Administration
  2. Click on Service Applications > SharePoint Search Server
  3. Run a Full Crawl on your content source(s)

Once they are done, your search results will load up just fine.

Today, saturday 06th April 2013, I and my friend This email address is being protected from spambots. You need JavaScript enabled to view it. (Ciccio for friends) are engaged to deploy a SharePoint solution in the Production enviroment. All is going done except a strange behavior of a component in home page.

After some checks into other environments, we are not able to find a solution of the problem. The only one way to find a possible solution is to debug the solution but we are in production environment. So, while Ciccio reassure the customer that we have the control of the problem, I start to collection informations how to remotly Debug the application.

First of all, we need to install into remote server (in our case, we select one front-end web server of production environment) the "Visual Studio 2010 Remote Debugger with Service Pack 1" tool. After configure the server with the Remote Debugger wizard, we are ready to start the dubug (the TCP ports are fortunately open to allow us to comunicate from another server).

After that, we need a server with Visual Studio Professional or Ultimate installed. We need to login with an user that have right permissions to add dlls into GAC of the Remote Server. We opened our solution and made to a build with debug mode. So, into bin folder, we have the .dll and .pdb files.

The next step is to copy the files into into the <dll name> directory stored into the GAC of the server . Actually, the GAC view is the following.

 

We need to change the GAC View to have a folder view. To do that, we must execute the following commands and the result is the next image.

Show/Hidden bash code

View source
 
 
 
start > run > cmd
type : "cd c:\windows\assembly"
type: "attrib -r -h -s desktop.ini"
type: "ren desktop.ini desktop.bak"
 

Now, from the "client" server, we need to navigate into the server GAC_MSIL folder to put the pdb and dll files. The server path is \\<ip address>\$c\windows\assembly\gac_msil\<dll name>\<dll version>.

Whenever we need to update the dll and pdb files, we make this steps:

  • Into the remote server, to unlock the dll, make an "iisreset /stop" command
  • Into the client server, copy the pdb and dll files from the bin folder to the remote dll path into gac_msil
  • Into the remote server, make an "iisreset /start" command.

Now, the last step is to run the Visual Studio debugger tool (into visual studio, click on debugger menu -> attach to process -> into qualifier field, insert the remote server ip address) and attacch to w3p processes of the remote server.

Magically, when we put a breack point, the circle turn red and we can debug the remote dll. We are very happy and with this way, we found the bug.

NOTE: our production environment is composed of one application server and two web front-end servers. All our test are executed on one web FE server. To exclued all request from users, we removed momentarily the FE from the balancer and to reach the FE from the "client server", we modify the hosts file of the "client server" adding an entry with the FE ip address and the application host name..

 

Have you ever written a timer job in SharePoint to read from or writing to a term store in Managed Metadata, you might have done so and faced the error:
"The current user has insufficient permissions to perform this operation"
Even if you try to run the code with SPSecurity.RunWithElevatedPrivileges(), or with your own account from Visual Studio, it will still give you the same problem.
The thing is, that the timer job runs with its own service, which is “SharePoint 2010 Timer”, see the below image.

The user running this service has to have access to the term store administrators in Central Administration, see the image below:

 

In SharePoint 2010, there is a WCF service utilizing ADO.NET Data Service called ListData.svc fulfilling this goal.  You can submit the query by providing the URL containing various commands like sorting, filtering, positioning....etc. 

List all objects of the site
http:/<sp>/_vti_bin/ListData.svc

List all items of the list
http://<sp>/_vti_bin/ListData.svc/ListName

List specific item of the list
http://<sp>/_vti_bin/ListData.svc/ListName(<index>)

List specific item's field value of the list
http://<sp>/_vti_bin/ListData.svc/ListName(<index>)/(<field>)

Filtering
http://<sp>/_vti_bin/ListData.svc/ListName?$filter=<field> <operator> <value>

Lookup field query
http://%3csp%3e/_vti_bin/ListData.svc/ListName?$expand=<LookupList>&$filter=<LookupList>/<LookupField> <operator> <value>

Range (example: getting from 20th to 25th products)
http://<sp>/_vti_bin/Products?$skip20&$top=5


Check MSDN Reference Using Microsoft ADO.NET Data Services for all query options(expand, orderyby, skip, top, filter), operators (eq, ne, gt, ge, lt, le, and, or, not.....), and functions.

In my case, I've used ListData.svc to retrive items from a list. It works fine when I used as filter a field with one word as display name but when I used a field with two or more words as display name I receive this error 400 Bad Request and with Fiddler I inspect the request and view the error:

Show/Hidden xml code

View source
 
 
 
<error xmlns="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
    <code/>
    <message xml:lang="it-IT">Syntax error at position 10.</message>
</error>
 
 
 

This is the request: "http://test.virtualsp.com/_vti_bin/ListData.svc/Omologations?$filter=startswith(Model Year,'mo')&$select=Model Year,Id".

Trying to resolve the problem, I've tested:

  • Use the single quote for the display name "http://test.virtualsp.com/_vti_bin/ListData.svc/Omologations?$filter=startswith('Model Year','mo')&$select='Model Year',Id": DOES NOT RESOLVE THE PROBLEM
  • Use the double quote for the display name "http://test.virtualsp.com/_vti_bin/ListData.svc/Omologations?$filter=startswith("Model Year",'mo')&$select="Model Year",Id": DOES NOT RESOLVE THE PROBLEM
  • Use the internal name of the field "http://test.virtualsp.com/_vti_bin/ListData.svc/Omologations?$filter=startswith(OMG_ModelYear,'mo')&$select=OMG_ModelYear,Id": DOES NOT RESOLVE THE PROBLEM
  • Use the display name removing the space from words "http://test.virtualsp.com/_vti_bin/ListData.svc/Omologations?$filter=startswith(ModelYear,'mo')&$select=ModelYear,Id": THIS RESOLVES THE PROBLEM

So, when you want use the ListData.svc and your fields display name has spaces, REMEMBER to remove it into the request and see this beautiful page.

Sometimes, the customer asks us to implement a particular field. In my case, the task is to have a field that show an editable table.


The specialness of this table is that it has only two editable columns but the editor can choices to add a different number of rows: this means that I need to implement a custom field that has an update panel that incapsule an asp Table.  For each row of the table, I must add two TextBox. Also there must be an "Add" button to add another row with other two text field.

To implement all, I need to define:

  • the xml (fldtypes_FeatureBenefitField.xml) to describe the field
  • the Field definition (FeatureBenefitField.cs): it extends the functionality of the SPFieldMultiColumn
  • the field control  (FeatureBenefitFieldControl.cs) that has the logic to manipulate the field
  • the render template (FeatureBenefitTemplateRender.ascx) that is the ascx that describes how render the field. I've defined two render template: one for the the creation and the edit of the item, another one for the view. Note: this file must be stored under the CONTROLTEMPLATES root mapped folder

 
A problem that I've found during the implementation is that when I interact with other fields or when I press on the add button, the values are lost. The workaround is to store into a property of the ViewState the number of row so I can reproduce the table and to restore the previous values I read the values into the Request.Form.
Another problem is that when I modify the renderTemplate and I make a deploy with Visual Studio, I don't see the updates. The problem is that when I deploy with Visual Studio, it makes only a Recycle of the Application Pool and the previous version of the template is still in use by SharePoint. So to resolve the problem, the keyword is "iisreset".
After the iisreset, the updated version of the render template is shown.

Here the code of the customization.

fldtypes_FeatureBenefitField.xml

Show/Hidden xml code

View source
 
 <?xml version="1.0" encoding="utf-8" ?>
<FieldTypes>
    <FieldType>
        <Field Name="TypeName">FeatureBenefitField</Field>
        <Field Name="TypeDisplayName">Feature Benefit</Field>
        <Field Name="TypeShortDescription">Feature Benefit field that show an editable table</Field>
        <Field Name="ParentType">MultiColumn</Field>
        <Field Name="FieldTypeClass">LucaCostante.SP.CF.FeatureBenefitField,LucaCostante.SP.CF, Version=1.0.0.0, Culture=neutral, PublicKeyToken=2cdef4b45abd6dec</Field>
        <Field Name="Sortable">TRUE</Field>
        <Field Name="Filterable">TRUE</Field>
        <Field Name="AllowBaseTypeRendering">TRUE</Field>
    </FieldType>
</FieldTypes>
 

FeatureBenefitField.cs

Show/Hidden csharp code

View source
 
 
 
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;
using Microsoft.SharePoint.Security;
using System.Security.Permissions;
 
namespace LucaCostante.SP.CF
{
    public class FeatureBenefitField : SPFieldMultiColumn
    {
        public FeatureBenefitField(SPFieldCollection fields, string fieldName) 
            : base(fields, fieldName) { }
 
        public FeatureBenefitField(SPFieldCollection fields, string typeName, string displayName) 
            : base(fields, typeName, displayName) { }
 
        public override object GetFieldValue(string value)
        {
            if (string.IsNullOrEmpty(value))
                return null;
            return new SPFieldMultiColumnValue(value);
        }
 
        public override BaseFieldControl FieldRenderingControl
        {
            [SharePointPermission(SecurityAction.LinkDemand, ObjectModel = true)]
            get
            {
                BaseFieldControl fieldControl = new FeatureBenefitFieldControl();
                fieldControl.FieldName = this.InternalName;
                return fieldControl;
            }
        }
        
    }
}
 
 
 

FeatureBenefitFieldControl.cs

Show/Hidden csharp code

View source
 
 
 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint.WebControls;
using Microsoft.SharePoint.Security;
using System.Security.Permissions;
using System.Collections;
using Microsoft.SharePoint;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using LucaCostante.SP.CF.CONTROLTEMPLATES;
 
namespace LucaCostante.SP.CF
{
    public class FeatureBenefitFieldControl : BaseFieldControl
    {
        private int numOfRows = 1;
 
        protected Table tableFeatBenefit;
        protected Table tableView;
        protected Button addButton;
 
 
        #region Properties
        protected override string DefaultTemplateName
        {
            get
            {
                if (this.ControlMode == SPControlMode.Display)
                {
                    return this.DisplayTemplateName;
                }
                else
                {
                    return "FeatureBenefitTemplate";
                }
            }
        }
 
        public override string DisplayTemplateName
        {
            get
            {
                return "FeatureBenefitTemplateForDisplay";
            }
            set
            {
                base.DisplayTemplateName = value;
            }
        }
 
        public override object Value
        {
            get
            {
                EnsureChildControls();
 
                GenerateTable();
                return GenerateCurrentFeatureBenefitValue();
            }
            set
            {
                EnsureChildControls();
                InitControls(value.ToString());
            }
        }
 
 
        #endregion
 
        #region Protected Methods
        protected override void CreateChildControls()
        {
            try
            {
                if (this.Field != null)
                {
                    base.CreateChildControls();
                    this.BindControls();
                }
 
                if (this.ControlMode == SPControlMode.New)
                {
                    if (!this.Page.IsPostBack)
                        this.InitControls();
                    else
                        this.EnsureChildControls();
                    this.AssignEvents();
                }
                else if (this.ControlMode == SPControlMode.Edit)
                {
                    if (!this.Page.IsPostBack)
                        this.InitControls();
                    this.EnsureChildControls();
                    this.AssignEvents();
                }
                else if (this.ControlMode == SPControlMode.Display)
                {
                    this.EnsureChildControls();
                    ViewTable();
                }
               
            }
            catch (Exception ex)
            {
                if (ex.GetType().Equals(typeof(SPFieldValidationException)))
                    throw new SPFieldValidationException(ex.Message);
 
            }
 
        }
 
       
        #endregion
 
 
 
        #region Private Methods
        private void BindControls()
        {
            if (this.ControlMode == SPControlMode.Display)
            {
                this.tableView = (Table)TemplateContainer.FindControl("tbl_FeatureBenefitForDisplay");
            }
            else
            {
                this.tableFeatBenefit = (Table)TemplateContainer.FindControl("tbl_FeatureBenefit");
                this.addButton = (Button)TemplateContainer.FindControl("btn_Add");
            }
        }
 
        private void AssignEvents()
        {
            this.addButton.Click += new EventHandler(lbtnAddButton_Click);
        }
 
        private void InitControls()
        {
            try
            {
                EnsureChildControls();
                GenerateTable();
            }
            catch (Exception ex)
            {
                if (ex.GetType().Equals(typeof(SPFieldValidationException)))
                    throw new SPFieldValidationException(ex.Message);
            }
        }
 
        private void InitControls(string couples)
        {
            string[] couple = couples.Split(new char[]{';','#'},StringSplitOptions.RemoveEmptyEntries);
            this.numOfRows = couple.Length;
            ViewState["RowsCount"] = this.numOfRows;
            GenerateTable();
 
            for (int i = 0; i < couple.Length; i++)
            {
                string[] currentCouple = couple[i].Split(new char[] { '€', 'ç' }, StringSplitOptions.RemoveEmptyEntries);
                if (currentCouple != null && currentCouple.Length > 0)
                {
                    ((TextBox)this.tableFeatBenefit.Rows[i+1].Cells[0].Controls[0]).Text = currentCouple[0];
                    ((TextBox)this.tableFeatBenefit.Rows[i+1].Cells[1].Controls[0]).Text = currentCouple[1];
                }
            }
 
        }
 
 
        private SPFieldMultiColumnValue GenerateCurrentFeatureBenefitValue()
        {
            SPFieldMultiColumnValue returnValue = new SPFieldMultiColumnValue(tableFeatBenefit.Rows.Count-1);
 
            for (int i=1;i< tableFeatBenefit.Rows.Count;i++)
            { 
                string feature=((TextBox) tableFeatBenefit.Rows[i].Cells[0].Controls[0]).Text;
                string benefit=((TextBox) tableFeatBenefit.Rows[i].Cells[1].Controls[0]).Text;
 
                if (!string.IsNullOrEmpty(feature) && !string.IsNullOrEmpty(benefit))
                    returnValue[i-1] = string.Format("{0}€ç{1}",feature,benefit);
            }
 
            return returnValue;
        }
 
        protected void lbtnAddButton_Click(object sender, EventArgs e)
        {
            ViewState["RowsCount"] = ++numOfRows;
            GenerateTable();
        }
 
        #endregion
 
 
       
 
        #region manipulate table
 
 
        private void ViewTable()
        {
            var value = SPContext.Current.Item[this.FieldName];
 
            if (value!=null)
            { 
                 TableRow row = null;
                 TableCell cell = null;
                
                row = new TableRow();
                cell = new TableCell();
                cell.ID = "FeatureHR";
                cell.Text = "Feature";
                row.Cells.Add(cell);
                cell = new TableCell();
                cell.ID = "BeneitHR";
                cell.Text = "Benefit";
                row.Cells.Add(cell);
                this.tableView.Rows.Add(row);
 
 
                string[] couple = value.ToString().Split(new char[] { ';', '#' }, StringSplitOptions.RemoveEmptyEntries);
                this.numOfRows = couple.Length;
 
                for (int i = 0; i < couple.Length; i++)
                {
                    string[] currentCouple = couple[i].Split(new char[] { '€', 'ç' }, StringSplitOptions.RemoveEmptyEntries);
                    if (currentCouple != null && currentCouple.Length > 0)
                    {
                        row = new TableRow();
 
                        cell = new TableCell();
                        cell.Text = currentCouple[0];
                        row.Cells.Add(cell);
                        cell = new TableCell();
                        cell.Text = currentCouple[1];
                        row.Cells.Add(cell);
 
                        this.tableView.Rows.Add(row);
                    }
                }
            }
 
        }
 
        private void GenerateTable()
        {
            if (ViewState["RowsCount"] != null)
                numOfRows = Convert.ToInt32(ViewState["RowsCount"].ToString());
 
 
            TableRow row = null;
            TableCell cell = null;
 
            if (tableFeatBenefit.Rows.Count == 0)
            {
                row = new TableRow();
                cell = new TableCell();
                cell.ID = "FeatureHR";
                cell.Text = "Feature";
                row.Cells.Add(cell);
                cell = new TableCell();
                cell.ID = "BeneitHR";
                cell.Text = "Benefit";
                row.Cells.Add(cell);
                this.tableFeatBenefit.Rows.Add(row);
            }
 
            const int colsCount = 2;
 
            // Now iterate through the table and add your controls
 
            for (int i = tableFeatBenefit.Rows.Count; i < numOfRows+1; i++)
            {
                row = new TableRow();
 
                for (int j = 0; j < colsCount; j++)
                {
                    cell = new TableCell();
                    TextBox tb = new TextBox();
 
                    tb.ID = "FeatBenTextBoxRow_" + i + "Col_" + j;
                    cell.Controls.Add(tb);
                    row.Cells.Add(cell);
                }
 
 
                this.tableFeatBenefit.Rows.Add(row);
            }
 
            //Set Previous Data on PostBacks
            SetPreviousData(numOfRows, colsCount);
 
            tableFeatBenefit.DataBind();
            
        }
 
 
        private void SetPreviousData(int rowsCount, int colsCount)
        {
            if (tableFeatBenefit != null)
            {
                for (int i = 1; i < rowsCount+1; i++)
                {
 
                    TextBox feature = (TextBox)tableFeatBenefit.Rows[i].Cells[0].FindControl("FeatBenTextBoxRow_" + i + "Col_0");
                    
                    var temp = (from string a in tableFeatBenefit.Page.Request.Form.AllKeys
                                where a.EndsWith("FeatBenTextBoxRow_" + i + "Col_0")
                                select a).FirstOrDefault();
 
                    if (temp!=null)
                        feature.Text = tableFeatBenefit.Page.Request.Form[temp];
 
                    TextBox benefit = (TextBox)tableFeatBenefit.Rows[i].Cells[1].FindControl("FeatBenTextBoxRow_" + i + "Col_1");
                    
                    temp = (from string a in tableFeatBenefit.Page.Request.Form.AllKeys
                            where a.EndsWith("FeatBenTextBoxRow_" + i + "Col_1")
                            select a).FirstOrDefault();
 
                    if (temp != null)
                        benefit.Text = tableFeatBenefit.Page.Request.Form[temp];
                }
            }
        }
        #endregion
    }
}
 
 
 

FeatureBenefitTemplateRender.ascx

Show/Hidden html5 code

View source
 
 
 
<%@ Assembly Name="$SharePoint.Project.AssemblyFullName$" %>
<%@ Assembly Name="Microsoft.Web.CommandUI, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register Tagprefix="Utilities" Namespace="Microsoft.SharePoint.Utilities" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register Tagprefix="asp" Namespace="System.Web.UI" Assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" %>
<%@ Import Namespace="Microsoft.SharePoint" %> 
<%@ Register Tagprefix="WebPartPages" Namespace="Microsoft.SharePoint.WebPartPages" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="FeatureBenefitTemplateRender.ascx.cs" Inherits="LucaCostante.SP.CF.CONTROLTEMPLATES.FeatureBenefitTemplateRender" %>
 
<SharePoint:RenderingTemplate ID="FeatureBenefitTemplate" runat="server">
    <Template>
        <asp:UpdatePanel ID="up_Table" runat="server">
            <ContentTemplate>
                <asp:table id="tbl_FeatureBenefit" runat="server"></asp:table>
                <asp:Button ID="btn_Add" runat="server" Text="+" />
            </ContentTemplate>
        </asp:UpdatePanel>
    </Template>
</SharePoint:RenderingTemplate>
 
<SharePoint:RenderingTemplate ID="FeatureBenefitTemplateForDisplay" runat="server">
  <Template>
    <asp:Table ID="tbl_FeatureBenefitForDisplay" runat="server" />
  </Template>
</SharePoint:RenderingTemplate>
 
 
 

Tuesday, 26 February 2013 16:35

Use a non default webfont

Written by

Some customers when ask us to develope the Intranet or other SharePoint sites, they want to use another font otherwise default fonts.

All websites can use the WebFonts (at this link, you can find all web fonts and can download it). To use a non-default webfont also under SharePoint , you must deploy it into your farm (in my example, i've added it under layouts mapped folder).

After that, must add into the css file the directive:

Show/Hidden css code

View source
 
 
 
@font-face {
    font-family: 'OpenSans';
    src: url('/_layouts/style/fonts/OpenSans-CondLight-webfont.eot');
    src: url('/_layouts/style/fonts/OpenSans-CondLight-webfont.eot?#iefix') format('embedded-opentype'),
         url('/_layouts/style/fonts/OpenSans-CondLight-webfont.woff') format('woff'),
         url('/_layouts/style/fonts/OpenSans-CondLight-webfont.ttf') format('truetype'),
         url('/_layouts/style/fonts/OpenSans-CondLight-webfont.svg#OpenSansCondensedLight') format('svg');
    font-weight: normal;
    font-style: normal;
}
 
 
 

 

In this example, I wanto to explain how to use the Client Object Model to retrieve User Profile Properties.

In my example, I have a list with some fields and one of this is a SPFieldUserValue (UserField is the internal name of my field).

Show/Hidden csharp code

View source
 
 
 
ClientContext clientContext = new ClientContext("htttp://intranet.domain022.dev");
clientContext.Credentials = new System.Net.NetworkCredential("username", "password", "domain");
 
 
Site siteCol = clientContext.Site;
Microsoft.SharePoint.Client.Web web = clientContext.Web;
clientContext.Load(web, w => w.Title, w => w.Language, w => w.ServerRelativeUrl);
clientContext.ExecuteQuery();
 
 
clientContext.Load(web, c => c.Lists);
clientContext.ExecuteQuery();
 
List list = web.Lists.GetByTitle("CustomList");
clientContext.Load(list);
clientContext.ExecuteQuery();
 
 
var userInfoList = clientContext.Web.SiteUserInfoList;
clientContext.Load(userInfoList);
 
CamlQuery camlQuery = new CamlQuery();
camlQuery.ViewXml = "<View/>";
Microsoft.SharePoint.Client.ListItemCollection items = list.GetItems(camlQuery);
clientContext.Load(items);
clientContext.ExecuteQuery();
 
foreach (Microsoft.SharePoint.Client.ListItem item in items)
{
    clientContext.Load(item);
    clientContext.ExecuteQuery();
    
    var temp = item["UserField"];
    
    var query = new CamlQuery { ViewXml = "<View Scope='RecursiveAll'><Query><Where><Eq><FieldRef Name='ID' /><Value Type='int'>" + ((FieldUserValue)temp).LookupId + "</Value></Eq></Where></Query></View>" };
    var user = userInfoList.GetItems(query);
    clientContext.Load(user);
    clientContext.ExecuteQuery();
    if (user.Count > 0)
    {
 
 
        //here I retrieve only Name property. You can iterate on all properties to view all User properties
        string name = user[0].FieldValues["Name"] as string;
        Console.WriteLine(string.Format("User found {0} with id {1}", name.Split('|').LastOrDefault(), user[0].Id));
    }
    else
    {
        Console.WriteLine(string.Format("User not found: {0} with id {1}", ((FieldUserValue)temp).LookupValue;, ((FieldUserValue)temp).LookupId.ToString()));
    }
}
 
 
 

Page 3 of 4