Friday, October 12, 2012

SharePoint and XSLT 1.0 - How to compare dates

==============================================================
UPDATE: Be aware that Microsofts's XSLT library date_templates.xsl contains a minor bug.
Using the "getDateFromDays" template will return NaN (not-a-number) when attempting to calculate the last day of the year (12/31).  All other days calculate correctly.
==============================================================
When it comes to performing date comparisons and calculations in SharePoint using XSLT 1.0 can be tricky, but here's a simple way

Navigate out to this document library
http://YourSite/Style%20Library/Forms/AllItems.aspx

And click on the "XSL Style Sheets" link
Microsoft has created an XSLT file with many handy templates for doing date calculations.
Download this Microsoft XSLT file date_templates.xsl and add it to the "XSL Style Sheets" folder.
Now locate the "ItemStyle.xsl" file and check it out for editing.  Add these styling blocks within the item you wish to transform

<!-- This is an example using the MS date_templates templates -->
<!-- Here it's calculating the date of tomorrow -->
<xsl:variable name="tomorrow">
  <xsl:call-template name="getDateFromDays">
  <!-- This template requires the date in the ISO format -->
  <xsl:with-param name="paramBaseDate" select="ddwrt:TodayIso()"/>
  <xsl:with-param name="paramDelta" select="1"/>
  </xsl:call-template>
</xsl:variable>

<!-- 1st step in date comparisons in XSLT 1.0 is to convert dates to numbers.  Stripping the dashes from an ISO date converts '2012-10-10' to the number '20121010' -->

<xsl:variable name="tomorrowAsNumber" select="(translate($tomorrow,'-',''))" />

<!-- The Content Query Web Part is returning a list of tasks that contain a field called "Due Date"
<xsl:variable name="listOfTasks" select="/dsQueryResponse/Rows/Row" />

<!-- Count the number of "Tasks Due Now" by converting the "Due Date" criteria to a number and comparing it to the "Tomorrow Number" using "less-than" -->
<xsl:variable name="countOfTasksDueNow" select="count($listOfTasks[translate(substring(@DueDate,1,10),'-','') &lt; $tomorrowAsNumber])" />

<!-- Count the number of "Tasks Due Tomorrow" by converting the "Due Date" criteria to a number and comparing it to the "Tomorrow Number" using "equals" -->
<xsl:variable name="countOfTasksDueTomorrow" select="count($listOfTasks[translate(substring(@DueDate,1,10),'-','') = $tomorrowAsNumber])" />

<!-- Count the number of "Future Tasks Due" by converting the "Due Date" criteria to a number and comparing it to the "Tomorrow Number" using "greater-than" -->

<xsl:variable name="countOfFutureTasks" select="count($listOfTasks[translate(substring(@DueDate,1,10),'-','') &gt; $tomorrowAsNumber])" />


SharePoint & Linq: More with less

Linq makes it easy to navigate thru a record set object of SharePoint List items.

// Using Statement

using System.Linq;

// Build the Query Object
SPQuery queryObject = new SPQuery();
queryObject.Query = 

@"<where>
   <contains>
      <fieldref name="FirstName">
         <value type="Text">Bob</value>
      </fieldref>
   </contains>
</where>
<orderby>
   <fieldref ascending="TRUE" name="Modified">
   </fieldref>
</orderby>";
Now, here's where the magic starts
Super Linq! -  Retrieving list items with a single line of code!

var results = list.GetItems(queryObject).Cast<splistitem>();


// Here's how to see if any records were returned
if (!results.Count().Equals(0))

// Want just the Last record?

var resultItem = list.GetItems(queryObject).Cast<SPListItem>().Last();

// Want just the First record?
var resultItem = list.GetItems(queryObject).Cast<SPListItem>().First();

Tuesday, March 20, 2012

How to Use "Add To All Content Types" When Creating List Columns with Code

The "Add To All Content Types" functionality can be achieved using the "AddFieldAsXml" method with the "AddToAllContentTypes" option, see below

   SPList currentList = currentWeb.Lists["DocLib"];
   SPField newField = currentList.Fields.CreateNewField(SPFieldType.Text.ToString(), "New Field2");
   currentList.Fields.AddFieldAsXml(newField.SchemaXml, true, SPAddFieldOptions.AddToAllContentTypes);
   currentList.Update();

I found this code and an excellent explanation on this blog http://blogs.microsoft.co.il/blogs/davidbi/archive/2009/01/22/sharepoint-add-a-spfield-to-all-the-content-types-in-a-splist.aspx

Tuesday, March 13, 2012

Fixing the Elements.xml file causing a deployment error

Here is the error that I got:
Error occurred in deployment step 'Activate Features': Operation is not valid due to the current state of the object
This occurs when you rename your namespace without also updating the "class" value in the Elements.xml file.

Here are the contents of the Elements.xml file:
<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <Receivers ListTemplateId="108">
    <Receiver>
      <Name>EmailReciever</Name>
      <Type>EmailReceived</Type>
      <Assembly>$SharePoint.Project.AssemblyFullName$</Assembly>
      <Class>MyNameSpace.MyProject.MyClass</Class>
      <SequenceNumber>10000</SequenceNumber>
    </Receiver>
  </Receivers>
</Elements>


Here is the Feature's code:
using System;
using System.Security.Permissions;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Security;
using Microsoft.SharePoint.Utilities;
using Microsoft.SharePoint.Workflow;
namespace MyNameSpace.MyProject
{

 public class MyClass : SPEmailEventReceiver
 {
  public override void EmailReceived(SPList list, SPEmailMessage emailMessage, String receiverData)
  {
   base.EmailReceived(list, emailMessage, receiverData);
  }
 }
}


The error occurs when the "class" value is not exactly "Namespace" dot "ClassName"  I've highlighted the pieces above, that make up the "class" value.  Since 2-part namespaces are common I've used that as an example.

Thursday, February 23, 2012

Comparing Fields to See if Values Have Changed in the ItemUpdating Method

You cannot get information about what was before the event in the '-ed' EventReceiver, only in the '-ing'.

So, within the public override void ItemUpdating(SPItemEventProperties properties) method...

- The "before" updating value is obtained like this;
var beforeValue = properties.ListItem["Column Name"].ToString();

- The "after" updating value is obtained like this;
var afterValue = properties.AfterProperties[properties.ListItem.Fields["Column Name"].InternalName];

Before making a beforeValue == afterValue comparison you may need to type check these values.

Changing the "Created By" Value in a SharePoint List Item

C#


// Where "item" is of type SPItem
item["Created By"] = web.EnsureUser("AD account name").ID;
item.UpdateOverwriteVersion();

Thursday, January 26, 2012

Toggle Debugging on/off for a Custom Code Web Part in SharePoint

C#
When I render my custom coded SharePoint Web Part, it helps to display extra information to assist me in troubleshooting. I can do this by constructing my web part like this...

...
using System.Web.UI.WebControls.WebParts;
...
public class MyCustomWebPart : WebPart
{
  protected override void CreateChildControls()
  {
    string paramOne = "One";
    this.Controls.Add(new LiteralControl("paramOne=" + paramOne + <br/>));
  }
}

So that my custom Web Part displays "paramOne=One"  Useful for debugging when I want know the value of internal parameters in code.

However, I don't want my user's to see my debugging information. I only want to turn it on in my local browser instance. I do this by adding to the Query String "?debug=true"  So on the end of my URL I append the Query String and update my Controls.Add statement with the following code.

bool.TryParse(Page.Request.QueryString["debug"], out debugOn);
if (debugOn) this.Controls.Add(new LiteralControl("paramOne=" + paramOne));

Wednesday, January 25, 2012

SharePoint Set the Value of a Yes/No Field in Code

C#


// Where "item" is of type SPItem
// how to read
bool result = Convert.ToBoolean(item["YesNoField"]);

// how to write
item["YesNoField"] = true;
item.Update();

Thursday, January 12, 2012

Available Headers in the SPEmailMessage Object

It couldn't find a complete list of email headers for Microsoft.SharePoint.Utilities.SPEmailHeader, so I've compiled one here;

Here's a sample usage that will return the raw email address of the sender...
// emailMessage is of the type SPEmailMessage
string EmailAddress = emailMessage.Headers["Return-Path"].ToString();
// will return "sender@domain.com"

string EmailAddress = emailMessage.Headers["From"].ToString();
// will return "Sender Contact Name <sender@domain.com>"


Ordinal Name Example
1 x-reciever "recipient@domain.com"
2 Received "from IncomingMailServer([IP])..."
3 Received "from IncomingMailServer([IP])..."
4 From "Sender Contact Name <sender@domain.com>"
5 To "Recipient Contact Name <recipient@domain.com>"
6 Subject "Subject Text"
7 Thread-Topic "Topic Text"
8 Thread-Index guid
9 Date ddd, dd mmm yyyyy hh:mm:ss +0000
10 Message-ID "UniqueId@IncomingMailServer"
11 Accept-Language "en-US"
12 Content-Language "en-US"
13 X-MS-Has-Attach "yes" or ""
14 X-MS-TNEF-Correlator ""
15 x-originating-ip "[IP]"
16 Content-Type ??
17 MIME-Version "1.0"
18 Return-Path "sender@domain.com

Here's a handy way to parse out the date...
DateTime sent = DateTime.Parse(emailMessage.Headers["Date"]);