in

vbCity Blogs

New (temp) place for vbCity Blogs

Andy Bonner's Blog

My SharePoint titbits and other things that take my fancy.

SharePoint/MOSS Color Picker Custom Field

 Copied from old Blog March 2008

Well it's been a long time since my last post and I though I'd better get my arse into gear and share some of the stuff I've been working on. As part of some development work I was doing for a colored SharePoint Calendar I had the need to allow users to select colors to have different types of Events displayed in and couldn't find a decent way of accomplishing this with the built in components of SharePoint, so I decided that this was an ideal candidate for a custom field type. Having made what I think is a useful addition to SharePoint I thought I'd share it with you. First I'll give you a little flavour of what it looks like before we dive into the code and how it all hangs together.

New Edit View 1

Here's how the field first looks in a New or Edit form

New Edit View DropDown

Here's some of the color choices available

New Edit View 2

And this is what it looks like once you've made some choices

So thats what the field looks like when your using it but how does it display you might be wondering, well here's how you'd see it in a list view

List View

Yep lovely but not very practicle is it, the real power comes when you use this value either within code or the xslt of the DataView WebPart, then you can produce some quite stunning results.

Color DataViewWebPart

custom xslt using the field values

Color Calendar

Custom calendar views using the field values through code

So Now that you've seen what you can do with it let's get into the code itself. In this example we have 5 files

  • SPColorsPickerFieldValue which inherits from SPFieldMultiColumnValue and holds the values and describes the properties for our field
  • SPColorsPickerField which inherits from SPFieldMultiColumn and is our field
  • SPColorsPickerFieldControl which inherits from BaseFieldControl and is the brains of the operation, basically the code behind for our ASCX
  • ControlTemplates_SPColorsPicker.ascx which defines a SharePoint RenderingTemplate element that tells it how to render our field in New or Edit mode
  • fldtypes_SPColorsPicker.xml which basically describes our field to SharePoint, telling it where it can be used, what it's called, what the assembly is called & also how it should be rendered in a list view

So how do we create a project for this custom field you ask. Well just create a Class Library project within VS2005 & add references for Microsoft.SharePoint and Microsoft.SharePoint.Security which you'll find in C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\12\ISAPI.

You also need to sign the assembly with a strong name key. Then you'll need to add classes for the field, field value & field control. Each of these classes needs a unique guid attribute. Here's the 3 classes you need

SPColorsPickerFieldValue (holds the values and describes the properties for our field)

 

using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.SharePoint;
using System.Runtime.InteropServices;


namespace SPColorsPicker
{ 
[CLSCompliant(false)]
[Guid("7B5DF376-E7DB-4353-AD51-7C5B69C675D6")]
[Serializable]
public class SPColorsPickerFieldValue : SPFieldMultiColumnValue
{ 
//how many properties are we storing
private const int numberOfFields = 2;
//required constructor
public SPColorsPickerFieldValue() 
: base(numberOfFields)
{
}
//required constructor
public SPColorsPickerFieldValue(string value) 
: base(value)
{
}


//property for storing the font color to use
public string FontColor
{ 
get
{ 
if (string.IsNullOrEmpty(this[0])) 
return "Black";
else 
return this[0];
}
set { this[0] = value; }
}
//property for storing the background color to use
public string BackgroundColor
{ 
get
{ 
if (string.IsNullOrEmpty(this[1])) 
return "White";
else 
return this[1];
}
set { this[1] = value; }
}
}
}

SPColorsPickerField (our field)

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;


namespace SPColorsPicker
{ 
[CLSCompliant(false)]
[Guid("01FB13ED-33F3-4caa-8CCF-42DAE083291F")]
public class SPColorsPickerField : SPFieldMultiColumn
{ 
//required constructor
public SPColorsPickerField(SPFieldCollection fields, string fieldName) 
: base(fields, fieldName)
{
}
//required constructor
public SPColorsPickerField(SPFieldCollection fields, string typeName, string displayName) 
: base(fields, typeName, displayName)
{
}
//tell it which control to use for rendering this field
public override BaseFieldControl FieldRenderingControl
{ 
[SharePointPermission(SecurityAction.LinkDemand, ObjectModel = true)]
get
{ 
BaseFieldControl fieldControl = new SPColorsPickerFieldControl();
fieldControl.FieldName = this.InternalName;
return fieldControl;
}
}
//returns the value of this field
public override object GetFieldValue(string value)
{ 
if (String.IsNullOrEmpty(value)) 
return null;
return new SPColorsPickerFieldValue(value);
}
}
}

SPColorsPickerFieldControl (the brains)

using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.SharePoint.WebControls;
using System.Web.UI.WebControls;
using System.Runtime.InteropServices;
using System.Reflection;
using System.Web.UI;
using System.Drawing;


namespace SPColorsPicker
{ 
[CLSCompliant(false)]
[Guid("F44DCD6A-D657-42e8-853A-ABC0713773C2")]
public class SPColorsPickerFieldControl : BaseFieldControl
{ 
protected DropDownList ddlBackground;
protected DropDownList ddlFont;
protected TextBox tbSampleText;
private SPColorsPickerFieldValue fieldValue;
protected override string DefaultTemplateName
{ 
//Get the RenderingTemplate in the ascx file
get { return "ColorsPicker"; }
}
public override object Value
{ 
get
{ 
EnsureChildControls();
if (this.ControlMode != SPControlMode.Display)
{ 
GetValues();
}
return fieldValue;
}
set
{ 
EnsureChildControls();
fieldValue = value as SPColorsPickerFieldValue;
}
}
private void GetValues()
{ 
//set this instances value to whats been selected
fieldValue.FontColor = ddlFont.SelectedItem.Text;
fieldValue.BackgroundColor = ddlBackground.SelectedItem.Text;
}
private void SetValues()
{ 
//set the controls values to whats currently stored in the field for an existing item
ddlFont.SelectedItem.Text = fieldValue.FontColor;
ddlBackground.SelectedItem.Text = fieldValue.BackgroundColor;
tbSampleText.ForeColor = Color.FromName(fieldValue.FontColor);
tbSampleText.BackColor = Color.FromName(fieldValue.BackgroundColor);
}
protected override void OnInit(EventArgs e)
{ 
//either get the value from an existing item or set it as a new value
if (ControlMode == SPControlMode.Edit || ControlMode == SPControlMode.Display)
{ 
if (this.ListItemFieldValue != null) 
fieldValue = this.ListItemFieldValue as SPColorsPickerFieldValue;
else 
fieldValue = new SPColorsPickerFieldValue();
}
if (ControlMode == SPControlMode.New)
{ 
fieldValue = new SPColorsPickerFieldValue();
}
base.OnInit(e);
}
protected override void OnLoad(EventArgs e)
{ 
base.OnLoad(e);
if (!Page.IsPostBack && ControlMode != SPControlMode.Display)
{ 
//fill the DropDowns with the list of available colors
List<string> allColors = new List<string>(Enum.GetNames(typeof(System.Drawing.KnownColor)));
List<string> systemColors = new List<string>();
foreach (MemberInfo member in (typeof(System.Drawing.SystemColors)).GetProperties())
{ 
systemColors.Add(member.Name);
}
foreach (string color in allColors)
{ 
if (!systemColors.Contains(color))
{ 
this.ddlBackground.Items.Add(color);
this.ddlFont.Items.Add(color);
}
}
//register scripts to update the preview client side
ClientScriptManager cs = this.Page.ClientScript;
if (!cs.IsClientScriptBlockRegistered(this.GetType(), "ChangeColors"))
{ 
StringBuilder csText = new StringBuilder();
csText.Append(" <SCRIPT type=text/javascript>");
csText.Append("function changeTextColor(dropdown, textboxID)");
csText.Append("{");
csText.Append("var x = document.getElementById(textboxID);");
csText.Append("var myindex = dropdown.selectedIndex;");
csText.Append("var SelValue = dropdown.options[myindex].value;");
csText.Append("x.style.color = SelValue;");
csText.Append("}");
csText.Append("function changeBackgroundColor(dropdown, textboxID)");
csText.Append("{");
csText.Append("var x = document.getElementById(textboxID);");
csText.Append("var myindex = dropdown.selectedIndex;");
csText.Append("var SelValue = dropdown.options[myindex].value;");
csText.Append("x.style.backgroundColor = SelValue;");
csText.Append("}");
csText.Append("</SCRIPT> ");
cs.RegisterClientScriptBlock(this.GetType(), "ChangeColors", csText.ToString(), false);
}
SetValues();
}
}
protected override void CreateChildControls()
{ 
if (Field == null) 
return;
base.CreateChildControls();
if (ControlMode == SPControlMode.Display) 
return;
//set the local vaiables
ddlFont = (DropDownList)TemplateContainer.FindControl("ddlFont");
ddlBackground = (DropDownList)TemplateContainer.FindControl("ddlBackground");
tbSampleText = (TextBox)TemplateContainer.FindControl("tbSampleText");
if (!Page.IsPostBack)
{ 
//add attributes to call the javascript functions when we choose different colors from the dropdown box's
//to update the preview client side
string textboxID = this.tbSampleText.ClientID;
ddlBackground.Attributes.Add("OnChange", string.Format("changeBackgroundColor(this,'{0}');", textboxID));
ddlFont.Attributes.Add("OnChange", string.Format("changeTextColor(this,'{0}');", textboxID));
}
}
//control how the field is rendered in display mode, doesn't overide list view display which is controlled
//by the DisplayPattern in the fldtypes xml file
protected override void RenderFieldForDisplay(HtmlTextWriter output)
{ 
StringBuilder sbldr = new StringBuilder();
sbldr.Append(" Sample Text");
output.Write(sbldr.ToString());
}
}
}

I've commented the code so you can see what's going on so i'm not going to go into more detail here.  

Compile your class library & install it in the GAC Now you can create the ascx file you'll need

ControlTemplates_SPColorsPicker.ascx

<%@ Control Language="C#" Debug="true" %>
<%@ Assembly Name="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register TagPrefix="SharePoint" Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" 
Namespace="Microsoft.SharePoint.WebControls" %>
<SharePoint:RenderingTemplate ID="ColorsPicker" runat="server"> 
<Template> 
<table> 
<tr> 
<td class="ms-formlabel"> 
Background Color</td>
<td> 
<asp:DropDownList ID="ddlBackground" Width="200px" runat="server">
</asp:DropDownList></td>
</tr>
<tr> 
<td class="ms-formlabel"> 
Text Color</td>
<td> 
<asp:DropDownList ID="ddlFont" Width="200px" runat="server">
</asp:DropDownList></td>
</tr>
</table>
<br />
<asp:TextBox ID="tbSampleText" runat="server" Font-Bold="True" ReadOnly="True">SAMPLE TEXT</asp:TextBox>
</Template>
</SharePoint:RenderingTemplate>

 Then copy the ascx file to C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\CONTROLTEMPLATES

Open your class library using Lutz Roeder's Reflector to get hold of the assembly name which you'll need in the next file you need to create

fldtypes_SPColorsPicker.xml

xml version="1.0" encoding="utf-8" ?>
<FieldTypes> 
<FieldType> 
<Field Name="TypeName">ColorsField>
<Field Name="ParentType">MultiColumnField>
<Field Name="TypeDisplayName">Colors PickerField>
<Field Name="TypeShortDescription">Pick Background and Font ColorsField>
<Field Name="UserCreatable">TRUEField>
<Field Name="ShowInListCreate">TRUEField>
<Field Name="ShowInDocumentLibraryCreate">TRUEField>
<Field Name="ShowInColumnTemplateCreate">TRUEField>
<Field Name="FieldTypeClass">SPColorsPicker.SPColorsPickerField, SPColorsPicker, Version=1.0.0.0, Culture=neutral, PublicKeyToken=3a4554e68e310c34Field>
<RenderPattern Name="DisplayPattern"> 
<Switch> 
<Expr> 
<Column/>
Expr>
<Case Value="">
Case>
<Default> 
<HTML> 0" HTMLEncode="TRUE"/>
<HTML>; background-color: ]]>HTML>
<Column SubColumnNumber="1" HTMLEncode="TRUE"/>
<HTML>">Sample Text]]>HTML>
Default>
Switch>
RenderPattern>
FieldType>
FieldTypes>

 Replace the value for FieldTypeClass with your assembly name then this file needs to be copied into C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\XML

Now all you need to do is either recycle the application pool or do an IISReset to have this new field type available to your SharePoint Lists

Create Column

Only published comments... Dec 13 2008, 09:13 AM by Andy Bonner

Comments

 

Mansour said:

Hi Andy,

Thank you for the good post; it is really helpful.

I am facing this issue:

""The name 'SecurityAction' does not exist in the current context""@ SPColorsPickerField.cs

any suggestions

May 12, 2009 1:29 AM

About Andy Bonner

 

Copyright 1998-2009 vbCity.com LLC
Powered by Community Server (Non-Commercial Edition), by Telligent Systems