Friday, October 28, 2011

How To: Programmatically generate a report and save the results as a PDF to SharePoint.

I had a requirement this week to run a report from within one of our WCF services, get it as a PDF file and then save it to a SharePoint library. To do this you have to use the reporting services ReportExecutionService to run the report and get the file, then use the SharePoint Copy service to store it in the library. Here's how:

1. Add a web reference to the service 
1.1 Right click on your project and click on Add Service Reference
 1.2 Click on the Advanced button in the bottom left
 1.3 Click on Add Web Reference
 1.4 In the URL box add the reference to
http://yourReportServer/reportserver/reportexecution2005.asmx?wsdl
 1.5 Give your service a name and click on Add Reference

2. Create the service call method

// create the service
ReportExecutionService rs = new ReportExecutionService();
rs.Credentials = EcmServices.CreateNetworkCredential();
rs.Url = ConfigurationSettings.AppSettings["ReportServerUrl"];


// Prepare report parameter.
ParameterValue[] parameters = new ParameterValue[1];
parameters[0] = new ParameterValue();
parameters[0].Name = "ID";
parameters[0].Value = id;  // this is a value I pass to the method


// render arguments
byte[] result = null;
string reportPath = "/My Reports/Report";
string format = "PDF";
string historyID = null;
string devInfo = @"<DeviceInfo><Toolbar>False</Toolbar></DeviceInfo>";
string encoding;
string mimeType;
string extension;
Warning[] warnings = null;
string[] streamIDs = null;


// create execution info
ExecutionInfo execInfo = new ExecutionInfo();
ExecutionHeader execHeader = new ExecutionHeader();
rs.ExecutionHeaderValue = execHeader;
execInfo = rs.LoadReport(reportPath, historyID);
rs.SetExecutionParameters(parameters, "en-us");
String SessionId = rs.ExecutionHeaderValue.ExecutionID;


// execute the report and get the rendered file as a byte array
result = rs.Render(format, devInfo, out extension, out encoding, out mimeType, out warnings, out streamIDs);
execInfo = rs.GetExecutionInfo();


if(result != null)
{
 SubmitFileToSharePoint(result, id);
}


As above, the results return as a byte[] and this can be used in the SharePoint Copy service to store the file.

3. Store the file using the SharePoint Copy service
You need to add a web reference to the SharePoint Copy service in the same way as you did for the ReportExecutionService. The URL for this service is: http://yourSharepointServer/_vti_bin/Copy.asmx
public static void SubmitFileToSharePoint(byte[] fileBytes, int id){
 // create the copy service
 Copy copyWS = new Copy();
 copyWS.Url = "
http://yourSharepointServer/_vti_bin/Copy.asmx";
 copyWS.Credentials = System.Net.NetworkCredential("username", "password", "domain");


 // create the file url
 string documentLibraryUrl = "
http://yourSharepointServer/Documents/Report_" + id + ".pdf";
 string[] destinationUrls = { documentLibraryUrl };


 // set metadata values on the file
 FieldInformation info1 = new FieldInformation();
 info1.DisplayName = "Report ID";
 info1.Value = id.ToString();
 FieldInformation[] info = { info1 };


 // create the result variable
 var copyResult = new CopyResult();
 CopyResult[] copyResults = { copyResult };


 // copy the file
 copyWS.CopyIntoItems(documentLibraryUrl, destinationUrls, info, fileBytes, out copyResults);
 copyWS.Dispose();

 if (copyResults[0].ErrorCode != CopyErrorCode.Success)
 {
  throw new SPException(string.Format("Error copying file to {0}. {1}", copyResults[0].DestinationUrl, copyResults[0].ErrorMessage));
 }
}

Thursday, October 13, 2011

How To: Stretch an iFrame to the size of its contents

I had a requirement to put a PageViewerControl inside a SharePoint 2007 page (which is rendered out as an iFrame) and the height of it must be set to the height of its contents. Now most browsers won't allow you to do this at all for security reasons and I would suggest finding another way to build this, but during my development I did get this little script working on a lot of the more common browsers. Not sure how it will do on IE8 or IE9 though...

<script type="text/javascript">
 // get the iframe
 var oFrame = document.getElementsByTagName("iframe")[0];

 function SetFrameHeight_FireFox(){ 
  try{
   // remove border and scrolling
   oFrame.setAttribute("frameborder","0");
   oFrame.setAttribute("scrolling","no");
 
   // set height and width
   var oBody = oFrame.contentWindow.document.body;
   document.getElementById("ifrm").style.height = oBody.scrollHeight + "px";
   document.getElementsByTagName("iframe")[0].style.width = "960px";
  }
  catch(e){
   window.status =  'Error: ' + e.number + '; ' + e.description;
  }
 }

 function SetFrameHeight_IE(){
  try{
   // set height and width
   var oBody = oFrame.document.body;
   document.getElementById("ifrm").style.height = ifrm.document.body.scrollHeight + (ifrm.document.body.offsetHeight - ifrm.document.body.clientHeight);
   document.getElementsByTagName("iframe")[0].style.width = "960px";
  
   // remove scrolling
   ifrm.document.body.setAttribute('scroll', 'no');
  }
  catch(e){
   window.status =  'Error: ' + e.number + '; ' + e.description;
  }
 }

 // check for browser type and call function when frame has finished loading.
 if(document.implementation && document.implementation.createDocument)
 {
  oFrame.setAttribute("onLoad","SetFrameHeight_FireFox()");
 }
 else
 {
  oFrame.setAttribute("onload","SetFrameHeight_IE()");
 
 }
</script>

Thursday, October 6, 2011

How To: SharePoint 2010 Exchange Rate Web Part

This is another web part which our clients frequently require which is not always available on the web, and when it is it's not what you're looking for. The workings of this is going to be really simple so you will be able to customize it easily for your needs. The web part will for now only display selected exchange rates. The RSS feed is provided by TheMoneyConverter.com



1. Create a Visual Web Part project
In Visual Studio, click on File > New > Project and select the Visual Web Part template from the SharePoint 2010 installed templates. Give your project a name e.g. CurrencyWebPart, click Ok and click Finish.



In your solution explorer you can rename the web part and its code files to suit your needs. I have renamed mine to CurrencyWebPart. Remember to update the properties in the .webpart file if you rename your solution elements otherwise you will get an issue with the SafeControl entries when trying to add the web part to a page.

2. Add the front-end controls

The following is the code for the user control .ascx file
<style type="text/css">
    .erBox
    {
        text-align:center;
        width:300px;
    }
    .erTitle, erItem, erDate
    {
        font-size:8pt;
        font-family:Verdana, Arial, Helvetica, Sans-Serif;
        color:#676767;
    }
   
    .erTitle
    {
        font-weight:bold;
        margin-bottom:5px;
    }
   
    .erLastUpdate
    {
        margin-top:5px;
        font-weight:bold;
    }
   
    .erDate, .erLastUpdate
    {
        font-style:italic;
    }
</style>

<div class="erBox">
    <div class="erTitle"><asp:Label runat="server" ID="lblTitle"></asp:Label></div>
    <div class="erItem">1 USD = <asp:Label runat="server" ID="lblUSD"></asp:Label> ZAR</div>
    <div class="erItem">1 GBP = <asp:Label runat="server" ID="lblGBP"></asp:Label> ZAR</div>
    <div class="erItem">1 EUR = <asp:Label runat="server" ID="lblEUR"></asp:Label> ZAR</div>
    <div class="erLastUpdate">Last update on:</div>
    <div class="erDate"><asp:Label runat="server" ID="lblDate"></asp:Label></div>
</div>


3. Add the code for rendering the page

The following code will get the Xml document from the URL and transform the data for the web part.

public partial class CurrencyUserControl : UserControl
{
 public const string _rssUrl = "
http://themoneyconverter.com/ZAR/rss.xml";
 protected void Page_Load(object sender, EventArgs e)
 {
  // get the nodes
  XmlDocument xdoc = CreateXmlDoc();
  string title = xdoc.SelectSingleNode("/rss/channel/title").InnerText;
  string buildDate = xdoc.SelectSingleNode("/rss/channel/lastBuildDate").InnerText;
  XmlNodeList nodeList = xdoc.SelectNodes("/rss/channel/item");

  DisplayExchangeRates(nodeList);
  lblTitle.Text = title;
  lblDate.Text = buildDate;
 }

 private void DisplayExchangeRates(XmlNodeList nodeList)
 {
  foreach (XmlNode node in nodeList)
  {
   string title = GetTitle(node.SelectSingleNode("title").InnerText);
   double value = GetValue(node.SelectSingleNode("description").InnerText);

   if (title.Equals("USD"))
    lblUSD.Text = value.ToString("##.00");
   else if (title.Equals("GBP"))
    lblGBP.Text = value.ToString("##.00");
   else if(title.Equals("EUR"))
    lblEUR.Text = value.ToString("##.00");
  }
 }

 private string GetTitle(string title)
 {
  string val = title;
  val = val.Substring(0, val.IndexOf("/"));
  return val;
 }

 private Double GetValue(string value)
 {
  // seeing that the value is in a description we have to hack it out there... yes I know it's nasty
  string val = value;
  val = val.Substring(val.IndexOf("=") + 2);
  val = val.Substring(0, val.IndexOf(" "));
  return 1 / double.Parse(val);
 }

 private XmlDocument CreateXmlDoc()
 {
  // create a reader and populate the document
  XmlReader reader = XmlReader.Create(_rssUrl);
  XmlDocument doc = new XmlDocument();
  doc.Load(reader);
  return doc;
 }
}


4. Deploy the solution

The solution can be deployed by right clicking the project in your solution explorer and clicking Deploy.

Wednesday, October 5, 2011

How To: SharePoint 2010 News Scroller Web Part

In this tutorial I will show you how to create a dynamic news scroller that will take the top news headlines and make them scroll upwards after a short period of time. This was done with a SharePoint 2010 Visual Web Part and some JavaScript from DynamicDrive.com.


For the purpose of this tutorial I will be hard-coding a URL from News24.com and using their latest articles. If you want the web part to be more dynamic in letting users choose their region or a different news site you can look at adding custom properties for the web part which can be set later on. View my How To: SharePoint 2010 Weather Web Part blog article to find out more on how this is done.

1. Create a new Visual Web Part project

Click on File > New > Project and select the Visual Web Part project template from the SharePoint 2010 Templates and click Ok.
Deploying as a Farm solution should be your only option so just click on Finish.
(I have renamed my web part to NewsScrollerWebPart for this tutorial)


2. Add the JavaScript for the scroller

Right click your project and click Add > SharePoint Mapped Folder and choose the TEMPLATES/LAYOUTS folder. Add a new normal folder inside with the name of your web part e.g. NewsScrollerWebPart. Create a new JScript file inside and paste the following code into it:





/***********************************************
* Pausing up-down scroller- © Dynamic Drive (
www.dynamicdrive.com)
* Visit
http://www.dynamicdrive.com/ for this script and 100s more.
***********************************************/

function pausescroller(content, divId, delay) {
    this.content = content //message array content
    this.tickerid = divId //ID of ticker div to display information
    this.delay = delay //Delay between msg change, in miliseconds.
    this.mouseoverBol = 0 //Boolean to indicate whether mouse is currently over scroller (and pause it if it is)
    this.hiddendivpointer = 1 //index of message array for hidden div
    document.write('<div id="' + divId + '" style="position: relative; overflow: hidden"><div class="innerDiv" style="position: absolute; width: 100%" id="' + divId + '1">' + content[0] + '</div><div class="innerDiv" style="position: absolute; width: 100%; visibility: hidden" id="' + divId + '2">' + content[1] + '</div></div>')
    var scrollerinstance = this
    if (window.addEventListener) //run onload in DOM2 browsers
        window.addEventListener("load", function () { scrollerinstance.initialize() }, false)
    else if (window.attachEvent) //run onload in IE5.5+
        window.attachEvent("onload", function () { scrollerinstance.initialize() })
    else if (document.getElementById) //if legacy DOM browsers, just start scroller after 0.5 sec
        setTimeout(function () { scrollerinstance.initialize() }, 500)
}

// -------------------------------------------------------------------
// initialize()- Initialize scroller method.
// -Get div objects, set initial positions, start up down animation
// -------------------------------------------------------------------

pausescroller.prototype.initialize = function () {
    this.tickerdiv = document.getElementById(this.tickerid)
    this.visiblediv = document.getElementById(this.tickerid + "1")
    this.hiddendiv = document.getElementById(this.tickerid + "2")
    this.visibledivtop = parseInt(pausescroller.getCSSpadding(this.tickerdiv))
    //set width of inner DIVs to outer DIV's width minus padding (padding assumed to be top padding x 2)
    this.visiblediv.style.width = this.hiddendiv.style.width = this.tickerdiv.offsetWidth - (this.visibledivtop * 2) + "px"
    this.getinline(this.visiblediv, this.hiddendiv)
    this.hiddendiv.style.visibility = "visible"
    var scrollerinstance = this
    document.getElementById(this.tickerid).onmouseover = function () { scrollerinstance.mouseoverBol = 1 }
    document.getElementById(this.tickerid).onmouseout = function () { scrollerinstance.mouseoverBol = 0 }
    if (window.attachEvent) //Clean up loose references in IE
        window.attachEvent("onunload", function () { scrollerinstance.tickerdiv.onmouseover = scrollerinstance.tickerdiv.onmouseout = null })
    setTimeout(function () { scrollerinstance.animateup() }, this.delay)
}


// -------------------------------------------------------------------
// animateup()- Move the two inner divs of the scroller up and in sync
// -------------------------------------------------------------------

pausescroller.prototype.animateup = function () {
    var scrollerinstance = this
    if (parseInt(this.hiddendiv.style.top) > (this.visibledivtop + 5)) {
        this.visiblediv.style.top = parseInt(this.visiblediv.style.top) - 5 + "px"
        this.hiddendiv.style.top = parseInt(this.hiddendiv.style.top) - 5 + "px"
        setTimeout(function () { scrollerinstance.animateup() }, 50)
    }
    else {
        this.getinline(this.hiddendiv, this.visiblediv)
        this.swapdivs()
        setTimeout(function () { scrollerinstance.setmessage() }, this.delay)
    }
}

// -------------------------------------------------------------------
// swapdivs()- Swap between which is the visible and which is the hidden div
// -------------------------------------------------------------------

pausescroller.prototype.swapdivs = function () {
    var tempcontainer = this.visiblediv
    this.visiblediv = this.hiddendiv
    this.hiddendiv = tempcontainer
}

pausescroller.prototype.getinline = function (div1, div2) {
    div1.style.top = this.visibledivtop + "px"
    div2.style.top = Math.max(div1.parentNode.offsetHeight, div1.offsetHeight) + "px"
}

// -------------------------------------------------------------------
// setmessage()- Populate the hidden div with the next message before it's visible
// -------------------------------------------------------------------

pausescroller.prototype.setmessage = function () {
    var scrollerinstance = this
    if (this.mouseoverBol == 1) //if mouse is currently over scoller, do nothing (pause it)
        setTimeout(function () { scrollerinstance.setmessage() }, 100)
    else {
        var i = this.hiddendivpointer
        var ceiling = this.content.length
        this.hiddendivpointer = (i + 1 > ceiling - 1) ? 0 : i + 1
        this.hiddendiv.innerHTML = this.content[this.hiddendivpointer]
        this.animateup()
    }
}

pausescroller.getCSSpadding = function (tickerobj) { //get CSS padding value, if any
    if (tickerobj.currentStyle)
        return tickerobj.currentStyle["paddingTop"]
    else if (window.getComputedStyle) //if DOM2
        return window.getComputedStyle(tickerobj, "").getPropertyValue("padding-top")
    else
        return 0
}


3. Create the JavaScript Links from the RSS XML

The script file uses a javascript array of links to render. We will basically just pull out the XML from the RSS feed, select the title and link nodes for each news headline and build up html links for the array:


public partial class NewsScrollerUserControl : UserControl
{
 // url of the RSS feed
 public const string _rssUrl = "
http://feeds.news24.com/articles/News24/TopStories/rss";
 protected void Page_Load(object sender, EventArgs e)
 {
  XmlDocument xdoc = CreateXmlDoc();
  XmlNodeList nodeList = xdoc.SelectNodes("/rss/channel/item");
  string script = BuildScript(nodeList);

  // register the script on the page
  ClientScriptManager csm = Page.ClientScript;
  csm.RegisterClientScriptBlock(this.GetType(), "ScrollerScript", script, true);
 }

 private String BuildScript(XmlNodeList nodeList)
 {
  // build the script
  StringBuilder sb = new StringBuilder();
  sb.Append("var pausecontent = new Array();");

  // add a link for each news headline
  int count = 0;
  foreach (XmlNode node in nodeList)
  {
   sb.Append(String.Format("pausecontent[{0}] = '<a target=\"_blank\" href=\"{1}\">{2}</a>'; ", count, node.SelectSingleNode("link").InnerText, node.SelectSingleNode("title").InnerText));
   count++;
  }

  return sb.ToString();
 }

 private XmlDocument CreateXmlDoc()
 {
  // create a reader and populate the document
  XmlReader reader = XmlReader.Create(_rssUrl);
  XmlDocument doc = new XmlDocument();
  doc.Load(reader);
  return doc;
 }
}


4. Add the Styles, JavaScript call method and script reference
This call method will make a call with your rendered links to the JavaScript file and bring back the scrolling HTML.

<script src="/_layouts/NewsScrollerWebPart/Scroller.js" type="text/javascript"></script>
<style type="text/css">
    #pscroller{
        width: 100%;
        height: 15px;
        border: 1px solid #ededed;
        padding: 3px;
        font-family:Verdana, Arial, sans-serif;
        font-size:8pt;
    }

    #pscroller a{
        text-decoration: none;
        color:#676767;
    }
   
    #pscroller a:hover{
        text-decoration: underline;
        color:#676767;
    }
</style>

<script type="text/javascript">
    new pausescroller(pausecontent, "pscroller", 3500);
</script>

Monday, October 3, 2011

How To: SharePoint 2010 List Definition with Managed Metadata fields

I recently had a request to create some custom list definitions for a site definition, and within these list definitions were some fields that had to link up to the Taxonomy of the company.

This is not as simple as just adding the fields to the Schema, you also need to create an event receiver that will attach to the FeatureActivated event handler of your feature in order to connect the fields up to the taxonomy. This sounds like quite a complicated solution but even though it is a lot of work, it is in fact really simple. Here's how...


1. Create the list definition project

In Visual Studio, choose to create a new project and select the List Definition project type under the SharePoint 2010 templates:




Choose Deploy as Farm Solution and click Finish

2. Update the name of your definition

After the project has been created you will see that Visual Studio has not inserted the correct names for your list definition. You can update the following to ensure your list has the correct names. (Use your list name wherever I used "MyListDefinition")


Change the actual list definition name from "ListDefinition1" to your list name in the solution explorer



Open the Elements.xml file and change the DisplayName and Description properties. Note: Don't change the value of the Name property as the comment suggest because this may cause an issue with folder names not being correct.

<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="
http://schemas.microsoft.com/sharepoint/">
    <!-- Do not change the value of the Name attribute below. If it does not match the folder name of the List Definition project item, an error will occur when the project is run. -->
    <ListTemplate
        Name="MyListDefinition"
        Type="10000"
        BaseType="0"
        OnQuickLaunch="TRUE"
        SecurityBits="11"
        Sequence="320"
        DisplayName="My List Definition"
        Description="This creates a MyListDefinition list"
        Image="/_layouts/images/itann.png"/>
</Elements>


Open the Schema.xml file and change the Title, Url fields

<?xml version="1.0" encoding="utf-8"?>
<List xmlns:ows="Microsoft SharePoint"
      Title="My List Definition"
      FolderCreation="FALSE"
      Direction="$Resources:Direction;"
      Url="Lists/My List Definition"
      BaseType="0"
      xmlns="
http://schemas.microsoft.com/sharepoint/">

3. Create a Content Type

Your managed metadata fields have to be inside a Content Type because it uses pre-defined system fields.

  1. Right click your project and click on Add > New Item...
  2. Select the Content Type template under the SharePoint 2010 templates, give it a name and click ok.
  3. Select "Item" as your base content type and click Finish. I usually pick "Item" as the base because it only contains the Title field which we will make a hidden field.
 
 
Open the Elements.xml file of your content type and update the Name, Group and Description properties.

<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="
http://schemas.microsoft.com/sharepoint/">
  <!-- Parent ContentType: Item (0x01) -->
  <ContentType ID="0x01002056f65066514e2e86ac6442eedd8ca8"
               Name="MyContentType"
               Group="MyContentTypes"
               Description="My Content Type"
               Inherits="TRUE"
               Version="0">
    <FieldRefs>
    </FieldRefs>
  </ContentType>
</Elements>


Inside the <FieldRefs> section of your content type, add the fields you are going to use in the list. These are just references to the fields we are still going to create, but it does not matter which ones you create first.

<FieldRefs>
  <FieldRef ID="{67051A64-C702-4FD6-A7BC-9EECFCCCC033}" Name="MyTextField"/>
  <FieldRef ID="{21E0A786-8F94-4A7D-98C3-A8B06B8C592A}" Name="MyUserField"/>
  <FieldRef ID="{B72AF39A-1F54-4041-93C2-F045CA8EDF04}" Name="MyTaxonomyField"/>
  <FieldRef ID="{6AAEB05A-2B38-482E-BC3A-FE2705E99709}" Name="MyTaxonomyFieldTaxHTField0"/>
 
  <!-- DO NOT CHANGE THESE NAMES OR IDS-->
  <FieldRef ID="{f3b0adf9-c1a2-4b02-920d-943fba4b3611}" Name="TaxCatchAll"/>
  <FieldRef ID="{8f6b6dd8-9357-4019-8172-966fcd502ed2}" Name="TaxCatchAllLabel"/>
</FieldRefs>


As you can see, for each ManagedMetadata field you need to add another <FieldRef> which will be used as a "Note" field for itself. This is used to store the actual data of the field as the Taxonomy one only makes a reference to the taxonomy.

You also need to add the bottom two fields called "TaxCatchAll" and "TaxCatchAllLabel". These are put in so that SharePoint search can find items of this content type. Note that since these two are system fields, you must NOT change the GUID's. You can use the standard Visual Studio GUID creator to generate the ID's for the rest of the fields found in Tools > Create GUID > Registry Format.

4. Add the Content Type and Fields to the List Schema

Delete everything in the <ContentTypes> section and add a reference to yours by copying the ID that was generated in the Elements.xml file of your content type.

<ContentTypes>
  <ContentTypeRef ID="0x01002056f65066514e2e86ac6442eedd8ca8" />
</ContentTypes>


Now, delete everything in the <Fields> section and add the references to the fields in the Elements.xml of your content type. We will start by adding the Title field and making it hidden. Then we will add field definitions for the rest:

<Fields>
  <!-- DO NOT CHANGE THE ID OF THE TITLE FIELD -->
  <Field ID="{fa564e0f-0c70-4ab9-b863-0177e6ddd247}"
   Type="Text"
   Name="Title"
   ShowInNewForm="FALSE"
   ShowInEditForm="FALSE"
   ShowInDisplayForm="FALSE"
   ShowInFileDlg="FALSE"
   DisplayName="$Resources:core,Title;"
   Sealed="TRUE"
   SourceID="
http://schemas.microsoft.com/sharepoint/v3"
   StaticName="Title">
  </Field>
 
  <Field ID="{67051A64-C702-4FD6-A7BC-9EECFCCCC033}" Type="Text" Name="MyTextField" DisplayName="My Text Field" />
  <Field ID="{21E0A786-8F94-4A7D-98C3-A8B06B8C592A}" Type="User" Name="MyUserField" DisplayName="My User Field" ShowField="NameWithPicture" />

  <!-- USE THE ID OF THE "NOTE" FIELD IN YOUR ELEMENTS.XML -->
  <Field ID="{6AAEB05A-2B38-482E-BC3A-FE2705E99709}"
  Type="Note"
  DisplayName="MyTaxonomyField_0"
  StaticName="MyTaxonomyFieldTaxHTField0"
  Name="MyTaxonomyFieldTaxHTField0"
  ShowInViewForms="FALSE"
  Required="FALSE"
  Hidden="TRUE"
  CanToggleHidden="TRUE"
  RowOrdinal="0" />
 
 <!-- USE THE ID OF THE "TAXONOMY" FIELD IN YOUR ELEMENTS.XML -->
  <Field ID="{B72AF39A-1F54-4041-93C2-F045CA8EDF04}"
   Type="TaxonomyFieldType"
   DisplayName="My Taxonomy Field"
   ShowField="Term1033"
   Required="TRUE"
   DisplaceOnUpgrade="TRUE"
   EnforceUniqueValues="FALSE"
   Group="_Custom"
   StaticName="MyTaxonomyField"
   Name="MyTaxonomyField">
 <Customization>
   <ArrayOfProperty>
  <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">{6AAEB05A-2B38-482E-BC3A-FE2705E99709}</Value>
  </Property>
   </ArrayOfProperty>
 </Customization>
  </Field>
</Fields>


You will see that the ID of the "Note" field is also added to the Customization metadata of the TaxonomyField. This tells it what note field to use.

5. Add the the field to the View of the List

Add your fields to the <ViewFields> section of every <View> like this:

<ViewFields>
  <FieldRef Name="MyTextField"></FieldRef>
  <FieldRef Name="MyUserField"></FieldRef>
  <FieldRef Name="MyTaxonomyField"></FieldRef>
</ViewFields>


6. Add the Event Receiver

Right click on your project and click Add > New Item...

Select the Event Receiver template from the SharePoint 2010 templates and click on Add. Select "List Events" as the type of receiver you want and choose the "A list was added" handler.
Add a reference to the Microsoft.SharePoint.Taxonomy.dll and add a using statement at the top of your class file.
Add the following method to your class that will connect the taxonomy field:

public void ConnectTaxonomyField(Guid fieldId, string listName, string termGroup, string termSetName, SPListEventProperties properties, string termName)
{
   if (properties.Web.Lists[listName].Fields.Contains(fieldId))
   {
    TaxonomySession session = new TaxonomySession(properties.Web.Site);

    if (session.DefaultKeywordsTermStore != null)
    {
     // get the default metadata service application               
     var termStore = session.DefaultKeywordsTermStore;
     var group = termStore.Groups.GetByName(termGroup);
     var termSet = group.TermSets.GetByName(termSetName);
     var term = termSet.GetByName(termName);

     TaxonomyField field = properties.Web.Lists[listName].Fields[fieldId] as TaxonomyField;
     // connect the field to the specified term               
     field.SspId = termSet.TermStore.Id;
     field.TermSetId = termSet.Id;
     field.TargetTemplate = string.Empty;
     field.AnchorId = term.Id;
     field.Update();
    }
    else
    {
     throw new TermStoreNotFoundException(string.Format("DefaultKeywordsTermStore not found in site {0}", properties.Web.Site.Url));
    }
   }
   else
   {
    throw new ArgumentException(string.Format("Field {0} not found in list {1}", fieldId, listName), "fieldId");
   }
}


Make a call to the ConnectTaxonomyField() method in your ListAdded event handler.

// Parameters are: Field ID, List Name, Term Group, Term Set, SPListEventProperties, Term you want to connect to
ConnectTaxonomyField(new Guid("{B72AF39A-1F54-4041-93C2-F045CA8EDF04}"), properties.ListTitle, "TermGroup", "TermSet", properties, "Term");


The last parameter is the Term you want to connect to in the Term Set. Not specifying this for a field will show you all the terms in that field.

Add the following classes to your file that will handle exceptions and create extension methods:

[Serializable]
public class TermStoreNotFoundException : Exception
{
 public TermStoreNotFoundException() { }
 public TermStoreNotFoundException(string message) : base(message) { }
 public TermStoreNotFoundException(string message, Exception inner)
  : base(message, inner) { }
 protected TermStoreNotFoundException(
  System.Runtime.Serialization.SerializationInfo info,
  System.Runtime.Serialization.StreamingContext context)
  : base(info, context) { }
}

public static class Extensions
{
 public static Group GetByName(this GroupCollection groupCollection, string name)
 {
  if (string.IsNullOrEmpty(name))
  {
   throw new ArgumentException("Not a valid group name", "name");
  }

  foreach (var group in groupCollection)
  {
   if (group.Name == name)
   {
    return group;
   }
  }
  throw new ArgumentOutOfRangeException("name", name, "Could not find the group");
 }

 public static TermSet GetByName(this TermSetCollection termSetCollection, string name)
 {
  if (string.IsNullOrEmpty(name))
  {
   throw new ArgumentException("Term set name cannot be empty", "name");
  }

  foreach (var termSet in termSetCollection)
  {
   if (termSet.Name == name)
   {
    return termSet;
   }
  }
  throw new ArgumentOutOfRangeException("name", name, "Could not find the term set");
 }

 public static Term GetByName(this TermSet termSet, string name)
 {
  if (string.IsNullOrEmpty(name))
  {
   throw new ArgumentException("Term name cannot be empty", "name");
  }

  for (int i = 0; i < termSet.Terms.Count; i++)
  {
   if (termSet.Terms[i].Name == name)
   {
    return termSet.Terms[i];
   }
  }
  throw new ArgumentOutOfRangeException("name", name, "Could not find the term set");
 }
}


7. Deploy the solution

You can simply deploy the solution by right clicking the project and clicking on Deploy.

That's it! You can now create an instance of the list to see your fields. It seems like a lot of work for just two fields, but once you get the basics right it goes quite fast.