Thursday, April 2, 2009

SharePoint Custom Field Controls

Creating custom field controls for Sharepoint at first looks abit hairy but like anything once you have created a couple they are not so hairy after all.

There are plenty of posts on field controls and Microsoft have some good stuff up aswell, but what I found very useful and time saving was finding this post Creating a Rendering Template that supports Edit and Display modes which describes many findings that are not well documented and would cause anyone a head ache trying to find this out by themselves.

So given all the good posts already up about the various overrides and so on in field controls I will just paste a field control I created for displaying videos as an example, you can see it in commerical action here ( http://nzte.govt.nz/features-commentary/Success-stories/Pages/Growing-with-NZTE-part-one.aspx ).

FeaturedVideo.ascx


<%@ Control Language="C#" %>
<%@ Register TagPrefix="PublishingWebControls" Namespace="Microsoft.SharePoint.Publishing.WebControls"
Assembly="Microsoft.SharePoint.Publishing, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register TagPrefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls"
Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<sharepoint:renderingtemplate id="FeaturedVideoControl" runat="server">
<Template>
<PublishingWebControls:EditModePanel ID="editModePanel" SuppressTag="true" runat="server">
<asp:Label id="messageLabel" CssClass="message" runat="server" />
<div>Video File</div>
<PublishingWebControls:AssetUrlSelector ID="urlVideoSelector" AllowExternalUrls="false" IsUrlRequired="true" ValidateUrl="false" runat="server" />
<div>Video Transcript Page</div>
<PublishingWebControls:AssetUrlSelector ID="urlVideoTranscriptPageSelector" IsUrlRequired="true" ValidateUrl="false" AllowExternalUrls="false" runat="server" /><br />
</PublishingWebControls:EditModePanel>
<PublishingWebControls:EditModePanel ID="viewModePanel" PageDisplayMode="Display" SuppressTag="true" runat="server">
<!-- Video Player -->
<div class="video-holder">
<div class="video-pod">
<div class="content">
<img id="previewImg" runat="server" height="85" width="233" />
<p class="video-show"><a id="videoAnchor" runat="server" title="Click here to open the video">Open Video Player</a></p>
</div>
</div>
<p class="video-abstract"><asp:Literal ID="videoAbstractLiteral" runat="server" /></p>
<p class="video-transcript"><a id="videoTranscriptAnchor" runat="server" title="Click here to view video transcript">Click here to view video transcript</a></p>
</div>
</PublishingWebControls:EditModePanel>
</Template>
</sharepoint:renderingtemplate>

FeaturedVideoControl.cs


namespace NZTE.SharePoint.FieldControls
{
public class FeaturedVideoControl : BaseFieldControl
{
#region Member Variables

protected EditModePanel editModePanel;
protected EditModePanel viewModePanel;
protected AssetUrlSelector urlVideoSelector;
protected AssetUrlSelector urlVideoTranscriptPageSelector;
protected HtmlImage previewImg;
protected HtmlAnchor videoAnchor;
protected HtmlAnchor videoTranscriptAnchor;
protected Literal videoAbstractLiteral;
protected Label messageLabel;

#endregion

#region Constants

private const string m_editModePanel = "editModePanel";
private const string m_viewModePanel = "viewModePanel";
private const string m_urlVideoSelector = "urlVideoSelector";
private const string m_urlVideoTranscriptPageSelector = "urlVideoTranscriptPageSelector";
private const string m_previewImg = "previewImg";
private const string m_videoAnchor = "videoAnchor";
private const string m_videoAbstractLiteral = "videoAbstractLiteral";
private const string m_videoTranscriptAnchor = "videoTranscriptAnchor";
private const string m_messageLabel = "messageLabel";
private const string m_controlTemplateName = "FeaturedVideoControl";
private FeaturedVideoFieldValue _value = new FeaturedVideoFieldValue();

#endregion

#region Property Overrides

///
/// Name of rendering template
///

protected override string DefaultTemplateName
{
get
{
return m_controlTemplateName;
}
}

///
/// Name of display rendering template
///

public override string DisplayTemplateName
{
get
{
return m_controlTemplateName;
}
}

///
/// Current value for control
///

public override object Value
{
get
{
EnsureChildControls();

_value.VideoUrl = urlVideoSelector.AssetUrl.ToString();
_value.TranscriptUrl = urlVideoTranscriptPageSelector.AssetUrl.ToString();

//Return the set value
return _value;
}

set
{
EnsureChildControls();

_value = new FeaturedVideoFieldValue(value.ToString());

urlVideoSelector.AssetUrl = _value.VideoUrl;
urlVideoTranscriptPageSelector.AssetUrl = _value.TranscriptUrl;
}
}

#endregion

#region Method Overrides

protected override void OnInit(EventArgs e)
{
CanCacheRenderedFieldValue = Constants.EnableBaseFieldControlCache;
base.OnInit(e);
}

///
/// Creates the child controls.
///

protected override void CreateChildControls()
{
if (this.Field != null && this.ControlMode == SPControlMode.Display)
{
base.CreateChildControls();
FindDisplayControls();
}

if (this.Field != null && this.ControlMode == SPControlMode.Edit)
{
base.CreateChildControls();
FindEditControls();
}
}

///
/// Validates this instance.
///

public override void Validate()
{
FeaturedVideoFieldValue field = _value;

<--validate each field and if any fail then set the following-->
if (field fails validation)
{
this.ErrorMessage = "Your error message";
IsValid = false;
return;
}
}

#endregion

#region Private Methods

///
/// Finds the display controls.
///

private void FindDisplayControls()
{
viewModePanel = (EditModePanel)Utilities.FindAndValidateControl(TemplateContainer, m_viewModePanel);
viewModePanel.PreRender += new EventHandler(viewModePanel_PreRender);
previewImg = (HtmlImage)Utilities.FindAndValidateControl(viewModePanel, m_previewImg);
videoAnchor = (HtmlAnchor)Utilities.FindAndValidateControl(viewModePanel, m_videoAnchor);
videoTranscriptAnchor = (HtmlAnchor)Utilities.FindAndValidateControl(viewModePanel, m_videoTranscriptAnchor);
videoAbstractLiteral = (Literal)Utilities.FindAndValidateControl(viewModePanel, m_videoAbstractLiteral);
}

///
/// Finds the edit controls.
///

private void FindEditControls()
{
editModePanel = (EditModePanel)Utilities.FindAndValidateControl(TemplateContainer, m_editModePanel);
messageLabel = (Label)Utilities.FindAndValidateControl(editModePanel, m_messageLabel);
urlVideoSelector = (AssetUrlSelector)Utilities.FindAndValidateControl(editModePanel, m_urlVideoSelector);
urlVideoTranscriptPageSelector = (AssetUrlSelector)Utilities.FindAndValidateControl(editModePanel, m_urlVideoTranscriptPageSelector);
}

///
/// Handles the PreRender event of the viewModePanel control.
///

/// The source of the event.
/// The instance containing the event data.
protected void viewModePanel_PreRender(object sender, EventArgs e)
{
EnsureChildControls();

if (ItemFieldValue != null)
{
_value = new FeaturedVideoFieldValue(ItemFieldValue.ToString());

if (!String.IsNullOrEmpty(_value.VideoUrl))
{
BindVideoControls(_value.VideoUrl);
BindTranscript(_value.TranscriptUrl);
}
else
viewModePanel.Visible = false;
}
else
viewModePanel.Visible = false;
}

#endregion
}
}

FeaturedVideoField.cs


namespace NZTE.SharePoint.FieldControls
{
public class FeaturedVideoField : SPFieldMultiColumn
{
///
/// Initializes a new instance of the class.
///

/// The fields.
/// Name of the field.
public FeaturedVideoField(SPFieldCollection fields, string fieldName)
: base(fields, fieldName)
{
}

///
/// Initializes a new instance of the class.
///

/// The fields.
/// Name of the type.
/// The display name.
public FeaturedVideoField(SPFieldCollection fields, string typeName, string displayName)
: base(fields, typeName, displayName)
{
}

///
/// Gets the field rendering control.
///

/// The field rendering control.
public override BaseFieldControl FieldRenderingControl
{
[SharePointPermission(SecurityAction.LinkDemand, ObjectModel = true)]
get
{
BaseFieldControl fieldControl = new FeaturedVideoControl();
fieldControl.FieldName = this.InternalName;

return fieldControl;
}
}
}
}

FeaturedVideoFieldValue.cs


namespace NZTE.SharePoint.FieldControls
{
public class FeaturedVideoFieldValue : SPFieldMultiColumnValue
{
private const int NUM_FIELDS = 2;

public FeaturedVideoFieldValue()
: base(NUM_FIELDS) { }

public FeaturedVideoFieldValue(string value)
: base(value) { }

public string VideoUrl
{
get { return this[0]; }
set { this[0] = value; }
}

public string TranscriptUrl
{
get { return this[1]; }
set { this[1] = value; }
}
}
}


FieldControls.xml




FeaturedVideoField
Featured Video Field
Featured Video field
Note
NZTE.SharePoint.FieldControls.FeaturedVideoField, NZTE.SharePoint, Version=1.0.0.0, Culture=neutral, PublicKeyToken=8ed5fb6d12664acd
TRUE