A Microsoft SharePoint 2007 custom field type for Microsoft CRM Dynamics 4.0
Article written by:
Karine Bosch, SharePoint Consultant at U2U Consultancy and
Patrick Tisseghem, Managing Partner at U2U
You can download the source code
here.
Introduction
Unlocking business data is a hot topic these days. Many organizations have come to the conclusion that a lot of the data that is
stored in line-of-business systems such as Microsoft CRM, SAP, mainframes and others, is simply not generally accessible by the
information workers. And yet, allowing them to easily find and act on that data would give them a real boost in their productivity;
all to the benefit of the company. In the past, IT department very often supported these users in their quest for information by
creating point-to-point applications; solutions that communicated directly with the native application programming interfaces of
the line-of-business systems. The introduction of Web Services and the whole wave of Service-Oriented Architectures (SOAs)
emphasized that this was not really the best approach. The power is to the middle-tier layers and the Business Data Catalog
that is part of Microsoft Office SharePoint Server 2007 is an excellent choice if your goal is to expose the business data
into the SharePoint user experience in a loosely-coupled way. This article demonstrates the power of the support you have in
MOSS 2007 for accomplishing this. It illustrates perfectly how SharePoint should be approached: as a development platform for
delivering server-side solutions for the information workers within your company.
In this walkthrough you will learn how you can create a SharePoint custom field
type that allows users to select an existing account from the CRM database. A download
link to the c# source code is available at the end of the article. SharePoint offers
you out of the box a variety of field types that you can use in lists, site columns
and content types. These are field types like text, number, choice, lookup, users
and even business data. Besides these standard field types you can also develop
your own custom field type. The primary function of a field type is storing information.
But there are cases in which you want the field type do something more like data
validation or application of business rules. You can also provide a custom field
type with a more complex user interface.
What is a custom field type?
A custom field type consists of many different parts. The hub of the custom field
is the field type class. If the custom field needs to store data in a more complex
way than For example a string or a number, this class will contain a reference to
a field value class. If the custom field offers a custom presentation, then this
class will also contain a reference to a field control class. In this field control
class you can choose to dynamically build your controls in code or refer to a RenderTemplate
defined in a user control.
When your custom field is all laid out it can be compiled into an assembly. To inform
SharePoint about the existence of your custom control and its structure you have
to create a field definition file that needs to be deployed to the C:\Program Files\Common
Files\Microsoft Shared\web server extensions\12\TEMPLATE\XML directory of SharePoint.
This definition file contains CAML markup containing a reference to the assembly
and the field type class.
When SharePoint starts up - after a boot of the server or an IISRESET – all field
type definitions are loaded and users will be able to use your custom field for
a column in a list or as a site column.
As SharePoint is all about features, the best way to deploy custom fields is by
working with a feature.
Why a CRM custom field type?
The custom field that we are going to develop in this walkthrough will give the
user the possibility to retrieve information about accounts stored in the CRM database.
As we expect to have a lot of accounts in the database, the user will be required
to fill out a part of the company name. After clicking the Search button, all accounts
containing the specified part in their company name will be retrieved and listed
in a dropdown list.
The user is then able to select an account from the dropdown list, which triggers
the custom field to display the address details of the selected account.
Behind the scenes the Business Data Catalog is used to retrieve the data
from the CRM database.
The Business Data Catalog
In the real world, business data is stored in many different ways and in a variety
of databases. The purpose of the Business Data Catalog is to make that business
data available into SharePoint.
The application definition file, which is included in the source code and which you can download at the top of this article,
has been developed by Patrick Tisseghem for his new book Inside Search. This book
will appear half way 2008. He used the Business Data Catalog Editor which was recently
released by Microsoft as part of the latest version of the MOSS 2007 SDK.
Developing the user control
As the custom field will be deployed as an assembly, it is a good idea to create
a class library project in Visual Studio 2005 or Visual Studio 2008. Prepare also
the folder structure that is required for a feature:
First of all we are going to create the visual user interface. Here you have two
possibilities: you can create the necessary controls like labels, text boxes and
buttons completely in code. But if your user interface is a bit more complex than
just a label and a text box, it is a good idea to design a user control. When working
the programmatic way, the user interface is compiled within the custom field assembly.
In this walkthrough the second technique is used. User controls must reside in the
CONTROLTEMPLATES directory of SharePoint so add a file with the ascx extension
to the corresponding sub folder you just created.
Add a reference to the SharePoint dll:
<@ assembly name="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ control language="C#" %>
<%@ register assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c"
namespace="Microsoft.SharePoint.WebControls" tagprefix="SharePoint" %>
User controls developed for use by SharePoint custom fields must contain one or more SharePoint RenderingTemplate
controls to tell SharePoint how to render your control.
<SharePoint:RenderingTemplate ID="CRMAccountControl" runat="server">
<Template>
<!—Add user interface here-->
</Template>
</SharePoint:RenderingTemplate>
All controls will reside in a HTML table for the ease of positioning the controls on the form.
<table class="ms-form" width="100%">
<colgroup>
<col width="100%" />
<!—add the controls here -->
</colgroup>
</table>
Now add the necessary controls:
- A label, textbox and button for the lookup of a filtered set of accounts
<tr>
<td>Enter a company name or part of a company name:</td>
</tr>
<tr>
<td>
<asp:TextBox ID="AccountTextBox" runat="server"
Width="70%" />
<asp:Button ID="SearchButton" runat="server" Width="26%"
Text="Search" />
</td>
</tr>
<tr>
<td style=”color: Red”>
<asp:Literal ID="WarningLabel" runat="server" Visible="false"
Text="Please, fill out the name or a part of the name of the account you are looking for." />
</td>
</tr>
- A dropdown list that will be populated with company names matching the search criterium:
<tr>
<td>Select CRM Account:</td>
</tr>
<tr>
<td>
<asp:DropDownList ID="AccountDropDownList" runat="server"
AutoPostBack="true" CssClass="ms-RadioText"
Width="100%" Enabled="false">
<asp:ListItem>Select an account...</asp:ListItem>
</asp:DropDownList>
<asp:TextBox ID="CompanyNameTextBox" runat="server" Width="100%"
Enabled="false" Visible="false" />
<asp:TextBox ID="AccountIdTextBox" runat="server" Visible="false" />
</td>
</tr>
The company name text box is there for editing purposes and stays hidden when a SharePoint list item is created.
- The literals and text boxes for the display of the account details. These controls stay hidden until an account is selected from the dropdown list.
<tr>
<td>
<asp:Literal ID="AddressLiteral" runat="server" Visible="false"
Text="Address details:" />
</tr>
<tr>
<td>
<asp:TextBox ID="AddressTextBox" runat="server" Visible="false"
Width="100%" Enabled="false" />
</td>
</tr>
<tr>
<td>
<asp:TextBox ID="PostalCodeTextBox" runat="server" Visible="false"
Width="30%" Enabled="false" /> <asp:TextBox
ID="CityTextBox" runat="server" Visible="false" Width="67%"
Enabled="false" />
</td>
</tr>
<tr>
<td>
<asp:TextBox ID="CountryTextBox" runat="server" Visible="false"
Width="100%" Enabled="false" />
</td>
</tr>
Developing the Field Value Class
Now we can start the development of the different classes. Add a reference to the System.Web.dll and to the Microsoft.SharePoint.dll.
The first class we will develop is the Field Value class. This class is only needed in case of complex custom fields, meaning that
they cannot be derived from SharePoint types like SPFieldText, SPFieldNumber or SPFieldBoolean. The Field Value class defines the
structure in which the data must be stored.
Add a class to the root of the Visual Studio project. This class must derive from the SharePoint base class SPFieldMultiColumnValue.
This class is an internal class and is not visible to users. Our custom data structure will contain values for the AccountId,
CompanyName, Address, PostalCode, City and Country.
In this class we need to override two constructors. The first constructor is the default constructor with no parameters. You have
to pass the number of fields in this field value class to the base constructor. Additionally the properties are initialized to an
empty string. The second constructor to override accepts a string value as parameter, which must also be passed to the base
constructor. The parameter is an initial value of the field. Internally it is split into an array.
Then 6 properties are defined. The property returns or stores a value from a certain position in the internal array. In this custom
field all properties are of type string but they can also be of other data types like integer, decimal, etc. Only the AccountId
property is shown in the code sample but the complete definition can be found in the source code.
public class CRMAccountFieldValue : SPFieldMultiColumnValue
{
private const int NUMBER_FIELDS = 6;
public CRMAccountFieldValue()
: base(NUMBER_FIELDS)
{
AccountId = string.Empty;
CompanyName = string.Empty;
Address = string.Empty;
PostalCode = string.Empty;
City = string.Empty;
Country = string.Empty;
}
public CRMAccountFieldValue(string value)
: base(value)
{
}
public string AccountId
{
get { return this[0]; }
set { this[0] = value; }
}
//other properties are omitted for brievety
}
Developing the Field Control Class
Next step is developing the Field Control class. This class is responsible for the rendering and proper functioning of the user
interface. It will hide and show controls when necessary, it will add event handlers to the buttons and execute the code behind
these event handlers.
Add a second class to the root of the Visual Studio project and let it derive from BaseFieldControl. This internal class renders
the field on a form page.
Override the DefaultTemplateName property and pass it the value in the ID attribute of the RenderingTemplate control from
the ascx control.
protected override string DefaultTemplateName
{
get { return “CRMAccountControl”; }
}
With this value SharePoint will look into all control templates located in the 12\TEMPLATE\CONTROLTEMPLATES folder and render the
corresponding control template.
Add the necessary using statements:
using System.Web.UI.WebControls;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;
Each control defined in the ascx control will also be defined in this class:
protected TextBox AccountTextBox;
protected Button SearchButton;
protected Literal WarningLabel;
protected DropDownList AccountDropDownList;
protected Literal AddressLiteral;
protected TextBox AccountIdTextBox;
protected TextBox CompanyNameTextBox;
protected TextBox AddressTextBox;
protected TextBox CityTextBox;
protected TextBox CountryTextBox;
protected TextBox PostalCodeTextBox;
You also need to override the CreateChildControl method:
protected override void CreateChildControls()
{
if (this.Field == null
|| this.ControlMode == SPControlMode.Display
|| this.ControlMode == SPControlMode.Invalid)
return;
base.CreateChildControls();
// get a reference to the different controls in the control template
AccountTextBox = TemplateContainer.FindControl("AccountTextBox") as TextBox;
if (AccountTextBox == null)
throw new ArgumentException("Account text box not found. “
+ “Please check if your control template is valid.");
SearchButton = TemplateContainer.FindControl("SearchButton") as Button;
if (SearchButton == null)
throw new ArgumentException("Search button not found. “
+ “Please check if your control template is valid.");
// add an event handler to this control
SearchButton.Click += new EventHandler(SearchButton_Click);
WarningLabel = TemplateContainer.FindControl("WarningLabel") as Literal;
if (WarningLabel == null)
throw new ArgumentException("Warning label not found.” +
+ “Please check if your control template is valid.");
AccountDropDownList =
TemplateContainer.FindControl("AccountDropDownList") as DropDownList;
if (AccountDropDownList == null)
throw new ArgumentException("Account dropdown list not found. “
+ “Please check if your control template is valid.");
// add an event handler to this control
AccountDropDownList.SelectedIndexChanged +=
new EventHandler(AccountDropDownList_SelectedIndexChanged);
AddressLiteral = TemplateContainer.FindControl("AddressLiteral") as Literal;
if (AddressLiteral == null)
throw new ArgumentException("AddressLiteral literal not found. “
+ “Please check if your control template is valid.");
// The rest of the controls is omitted for brievety.
// ...
}
The first statement is a validation of the display mode of the field. When a new item is created, the display mode of the field is
New. When an item is viewed, the display mode of the field is Display. When an item is edited, its display mode is Edit. In this
sample the rendering of the user control will only take place when the field is in Edit or Display mode. How the field is rendered
when in display mode will explained later in this article.
Then each control is looked up in the user control. The TemplateContainer property, which is a member of the BaseFieldControl
base class, contains a reference to the RenderingTemplate control. Use the FindControl method to get the instance of each control.
If the instance of a control cannot be found, throw an exception.
The code sample also adds a Click event handler to the Search button and a SelectedIndexChanged event handler to the account
dropdown list. The implementation of these event handlers will be explained a bit later in this section.
Another property to override is the Value property. It gets or sets the value of the field in the user interface.
public override object Value
{
get
{
EnsureChildControls();
CRMAccountFieldValue field = new CRMAccountFieldValue();
// set the account value
bool fillout = false;
if (AccountDropDownList != null && AccountDropDownList.SelectedIndex > 0)
{
fillout = true;
field.CompanyName = AccountDropDownList.SelectedItem.Text;
field.AccountId = AccountDropDownList.SelectedValue;
}
else if (CompanyNameTextBox.Visible && CompanyNameTextBox.Text.Length > 0
&& AccountIdTextBox.Text.Length > 0)
{
fillout = true;
field.CompanyName = CompanyNameTextBox.Text;
field.AccountId = AccountIdTextBox.Text;
}
if (fillout)
{
field.Address = AddressTextBox.Text;
field.City = CityTextBox.Text;
field.Country = CountryTextBox.Text;
field.PostalCode = PostalCodeTextBox.Text;
}
return field;
}
set
{
EnsureChildControls();
if (value != null && !string.IsNullOrEmpty(value.ToString()))
{
CRMAccountFieldValue field =
new CRMAccountFieldValue(value.ToString());
if (!string.IsNullOrEmpty(field.AccountId))
{
AccountIdTextBox.Text = field.AccountId;
CompanyNameTextBox.Text = field.CompanyName;
AddressTextBox.Text = field.Address;
CityTextBox.Text = field.City;
CountryTextBox.Text = field.Country;
PostalCodeTextBox.Text = field.PostalCode;
}
SetControlVisibility(field.AccountId);
}
else
{
SetControlVisibility(Guid.Empty.ToString());
}
}
}
The getter executes a call to the EnsureChildControls. This method checks if the child controls are already created. If not it
creates the child controls. A new object of type CRMAccountFieldValue is created and all fields are filled out based on values
in the account dropdown list or the company name text box. If the control is in New mode the account dropdown list will be visible.
If an account is selected, the values for the other properties can be set. If the control is in Edit mode the company name text box
is visible. If a company is filled out the values for the other properties can be set.
The setter also calls the EnsureChildControls method. Then the validation of the incoming value takes place. If the value is not null
or empty, an object of type CRMAccountFieldValue is created and the incoming value is passed in. If a value comes in, it means that the
list item is in Edit mode. In that case a certain number of text boxes are filled out. The visibility of the different controls is handled
in the private method SetControlVisibility and is based on the value of the account id and whether the item is in Edit mode or in New mode.
{
if (accountID == Guid.Empty.ToString())
{
// this means that no account is selected
AccountDropDownList.Visible = true;
CompanyNameTextBox.Visible = false;
AddressLiteral.Visible = false;
AddressTextBox.Visible = false;
CityTextBox.Visible = false;
CountryTextBox.Visible = false;
PostalCodeTextBox.Visible = false;
}
else
{
switch (this.ControlMode)
{
case SPControlMode.New:
// this means another country is selected
PopulateCRMAccountDetails(accountID);
AccountDropDownList.Visible = true;
CompanyNameTextBox.Visible = false;
break;
case SPControlMode.Edit:
AccountDropDownList.Visible = false;
CompanyNameTextBox.Visible = true;
break;
}
AddressLiteral.Visible = true;
AddressTextBox.Visible = true;
CityTextBox.Visible = true;
CountryTextBox.Visible = true;
PostalCodeTextBox.Visible = true;
}
}
If the account id is empty, the account dropdown list is made visible and the address detail controls are hidden. If the account
id contains a value all address detail controls are made visible. Additionally if the control is in New mode, account details are
looked up in the CRM database via the Business Data Catalog. The account dropdown list is kept visible and the company name text
box is hidden. If the control is in Edit mode, the account dropdown list is hidden and the company name text box is shown.
Next implement the Click event handler for the Search button. If the user filled out a value in the account text box, all accounts
containing that string in their company name are returned and listed in the account dropdown list. For this purpose the private
method PopulateCRMAccounts is called. This method will be explained in detail in a moment. If the account text box is empty, no
lookup in the CRM database can be performed and a warning is displayed.
void SearchButton_Click(object sender, EventArgs e)
{
if (AccountTextBox.Text.Length > 0)
{
WarningLabel.Visible = false;
AccountDropDownList.Enabled = true;
PopulateCRMAccounts(AccountTextBox.Text);
}
else
{
WarningLabel.Visible = true;
AccountDropDownList.Enabled = false;
}
SetControlVisibility(Guid.Empty.ToString());
}
Now implement the event handler for the SelectedIndexChanged event of the account dropdown list. This method ensures that the child
controls are created and calls the SetControlVisibility method passing the selected account to it.
void AccountDropDownList_SelectedIndexChanged(object sender, EventArgs e)
{
EnsureChildControls();
SetControlVisibility(AccountDropDownList.SelectedValue);
}
The PopulateCRMAccounts method accepts one argument containing a company name or part of a company name. This method uses the
Business Data Catalog object model to populate the account dropdown list. Therefore you need to add a reference to the
Microsoft.Office.Server.dll and the Microsoft.SharePoint.Portal.dll. Both assemblies are located in the 12\ISAPI folder
of SharePoint. Add also the following using statements at the top of this class file.
using Microsoft.Office.Server.ApplicationRegistry.Infrastructure;
using Microsoft.Office.Server.ApplicationRegistry.MetadataModel;
using Microsoft.Office.Server.ApplicationRegistry.SystemSpecific.Db;
using Microsoft.Office.Server.ApplicationRegistry.Runtime;
The Business Data Catalog is instantiated and the method GetAccounts method on the Account entity is executed. More
detailed information on the BDC object model can be found in Chapter 6 of Patrick Tisseghems book Inside Search.
private void PopulateCRMAccounts(string partName)
{
AccountDropDownList.Items.Clear();
AccountDropDownList.Items.Add("Select an account...");
//connect to the LobSystemInstance that represents the CRM business
// application in the BDC
NamedLobSystemInstanceDictionary instances =
ApplicationRegistry.GetLobSystemInstances();
LobSystemInstance instance = instances["CRM_Accounts_Instance"];
// Connect to the CRM account entity
Entity entity = instance.GetEntities()["Account"];
// Find and execute the method to get a set of accounts returned
Method method = entity.GetMethods()["GetAccounts"];
MethodInstance methodinstance =
method.GetMethodInstances()["GetAccountsInstance"];
FilterCollection filters = method.GetFilters(methodinstance);
WildcardFilter filter = (WildcardFilter)filters[0];
filter.Value = string.Format("%{0}%", AccountTextBox.Text);
DbEntityInstanceEnumerator accounts =
(DbEntityInstanceEnumerator)entity.FindFiltered(filters, instance);
// loop through the accounts and populate the accounts dropdown
while (accounts.MoveNext())
{
DbEntityInstance account = (DbEntityInstance)accounts.Current;
AccountDropDownList.Items.Add(
new ListItem(account.GetFormatted("name").ToString(),
account.GetFormatted("accountid").ToString()));
}
}
The PopulateCRMAccountDetails method accepts an account id as incoming argument. The account details are looked up via the
BDC by executing the GetAccount method of the CRM Account entity.
private void PopulateCRMAccountDetails(string accountId)
{
// connect to the LobSystemInstance that represents the CRM Accounts
// business application in the BDC
NamedLobSystemInstanceDictionary instances =
ApplicationRegistry.GetLobSystemInstances();
LobSystemInstance instance = instances["CRM_Accounts_Instance"];
// Connect to the CRM Account entity
Entity entity = instance.GetEntities()["Account"];
// Find and execute the method to get the account details
Method method = entity.GetMethods()["GetAccount"];
MethodInstance methodinstance =
method.GetMethodInstances()["GetAccountInstance"];
Object[] args = methodinstance.GetMethod().CreateDefaultParameterInstances(
methodinstance);
args[0] = accountId;
DbEntityInstanceEnumerator accounts =
(DbEntityInstanceEnumerator)entity.Execute(methodinstance,
instance, ref args);
// As account id is used to find account details, you can be sure only one
// account is returned
accounts.MoveNext();
DbEntityInstance account = (DbEntityInstance)accounts.Current;
AddressTextBox.Text = account.GetFormatted("address1_line1").ToString();
PostalCodeTextBox.Text =
account.GetFormatted("address1_postalcode").ToString();
CityTextBox.Text = account.GetFormatted("address1_city").ToString();
CountryTextBox.Text = account.GetFormatted("address1_country").ToString();
}
Developing the Field Type Class
Now it is time to create the Field Type class, which is the coordinating class of the custom field. Add another class to the
Visual Studio project and let it derive from SPFieldMultiColumn because the value of this field consist of more than one column.
Implement two constructors:
public CRMAccountField(SPFieldCollection fields, string fieldName)
: base(fields, fieldName)
{
}
public CRMAccountField(SPFieldCollection fields, string typeName,
string displayName)
: base(fields, typeName, displayName)
{
}
Then override the GetFieldValue method. This is necessary to make the custom field type aware that there is a Field Value class. If
the incoming string is not null or empty an instance of type CRMAccountFieldValue is created.
public override object GetFieldValue(string value)
{
if (string.IsNullOrEmpty(value))
return null;
return new CRMAccountFieldValue(value);
}
Then override the FieldRenderingControl property and return a control of type CRMAccountFieldControl to indicate which
control to render for this custom field type.
public override BaseFieldControl FieldRenderingControl
{
get
{
BaseFieldControl control = new CRMAccountFieldControl();
control.FieldName = this.InternalName;
return control;
}
}
Also override the GetValidatedString method. In this method you can check whether the user has set a column of this custom type as
required. If so, the field should contain a value. If the column of this type contains a value, check that the value is of the
correct type, i.e. CRMAccountFieldValue.
If the value is of the correct type and the column is defined as required, check that a company has been selected.
public override string GetValidatedString(object value)
{
if (value == null)
{
if (this.Required) throw new SPFieldValidationException(
"Invalid value for required field.");
return string.Empty;
}
else
{
CRMAccountFieldValue field = value as CRMAccountFieldValue;
// if no value obtained, error in the field
if (field == null) throw new ArgumentException("Invalid value.");
// if the field is defined as required field
if (this.Required)
{
// make sure that a company is selected
if (string.IsNullOrEmpty(field.CompanyName))
throw new SPFieldValidationException(
"A CRM account is required.");
}
return value.ToString();
}
}
All code has been written now. Sign your assembly and build it.
Developing the Field Type Class
The custom field type definition is an XML file that contains CAML markup to inform SharePoint about the existence of the custom field type.
Each time SharePoint loads it checks the 12\TEMPLATE\XML directory for XML files containing field type definitions. Field type
definitions always start with the CAML element <FieldTypes>. Within that root element one or more <FieldType> elements can occur.
The <Field> elements contain necessary information for SharePoint like the name of the field, the parent field type, the display
name and a reference to the assembly and Field Type class.
The <RenderPattern> element in this example contains rendering information for the field when it is in display mode.
Columns 1, 4 and 5 will be shown separated by a comma. Going back to the Field Type Value class you will see that these are the
column numbers for the company name, the city and the country.
<?xml version="1.0" encoding="utf-8" ?>
<FieldTypes>
<FieldType>
<Field Name="TypeName">CRMAccount</Field>
<Field Name="ParentType">MultiColumn</Field>
<Field Name="TypeDisplayName">CompanyName, city</Field>
<Field Name="FieldEditorUserControl">CRMAccountControl</Field>
<Field Name="TypeShortDescription">
CRM account custom field containing Company name and address information.
</Field>
<Field Name="UserCreatable">TRUE</Field>
<Field Name="FieldTypeClass">U2U.SharePoint.CRM.CustomFields.CRMAccountField,
U2U.SharePoint.CRM.Account.CustomFields, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=b014aa8fd23dd3de</Field>
<RenderPattern Name="DisplayPattern">
<Switch>
<Expr>
<Column />
</Expr>
<Case Value="" />
<Default>
<Column SubColumnNumber="1" HTMLEncode="TRUE" />
<HTML><![CDATA[, ]]></HTML>
<Column SubColumnNumber="4" HTMLEncode="TRUE" />
<HTML><![CDATA[, ]]></HTML>
<Column SubColumnNumber="5" HTMLEncode="TRUE" />
</Default>
</Switch>
</RenderPattern>
</FieldType>
</FieldTypes>
toAlways prefix the file name of your own custom field types with fldtypes_. For this custom field type I gave it the name
fldtypes_crm_account.xml.
Deploying the custom field
Now it is time to deploy the custom field. There are 3 steps to perform:
- The assembly for the custom field needs to be deployed in the global assembly cache.
- The ascx control needs to be copied to the 12\TEMPLATE\CONTROLTEMPLATES directory.
- The fldtypes_crm_account.xml file needs to be copied to the 12\TEMPLATE\XML directory.
When deploying the custom field type for the first time, you have to perform an IISRESET because SharePoint loads all of the existing
field types, based on the fldtypes_ definition files. When deploying updates to the assembly or ascx user control the recycling of
the application pool is sufficient. If you need to modify the fldtypes_ definition file, an additional is IISRESET is required.
Testing the custom field
Open your SharePoint site and create a new custom list. Add a field or two, and the CRM account custom field.
Add a new item to the list. Fill out part of a company name and click the Search button. Select an account from the dropdown list
and the account details will be displayed.
If you didn’t fill out part of a company name before clicking the Search button, you get a warning that the search could not be
performed.
When the item is added and you are returned to the All Items view, you will see that the custom field displays company name, city and country,
as you defined in the DisplayPattern of the field definition.
Try to edit the item. You will notice that all account details are filled out and that the company name is displayed in a text box.
If you want to change the value of the custom field, you can simply fill out part of the new company name and execute a search. The
account combo box will be shown populated with account, from where you can select another account.