A couple of months ago I did a blog post about Creating custom datatypes using the umbraco usercontrol wrapper , I mentioned in that post that there was also an other way of creating a custom datatype. So in this post I’ll try to show you how to create a datatype using the 3 classes way. One of the main differences between this approach and the wrapper is that you’ll be able to have settings for your datatype.
I made a very basic datatype, the char limit datatype I’ll just show how I created that one.
First step would be to create a new project in visual studio (I tend to start a new class library, but web application should also be fine) and reference the necessary umbraco assemblies (so make sure you have those, just download v4).
Here is how the solution explorer looks when the char limit solution is opened.
The umbraco assemblies that needs to be referenced are businesslogic, cms, interfaces, umbraco.Datalayer and umbraco.editorControls (you can find these in the bin directory of umbraco).
As you can notice in the solution explorer the projects contains 3 files.
- charLimitDataEditor.cs
- charLimitDataType.cs
- charLimitPrevalueEditor.cs
These are 3 classes (that’s wy I call it the 3 classes way) implementing the necessary umbraco interfaces.
I’ll start by showing the contents of charLimitDataType.cs
using System;
using System.Collections.Generic;
using System.Text;
namespace Nibble.Umb.Datatypes.CharLimit
{
public class charLimitDataType : umbraco.cms.businesslogic.datatype.BaseDataType, umbraco.interfaces.IDataType
{
private umbraco.interfaces.IDataEditor _Editor;
private umbraco.interfaces.IData _baseData;
private charLimitPrevalueEditor _prevalueeditor;
public override umbraco.interfaces.IDataEditor DataEditor
{
get
{
if (_Editor == null)
_Editor = new charLimitDataEditor(Data, ((charLimitPrevalueEditor)PrevalueEditor).Configuration);
return _Editor;
}
}
public override umbraco.interfaces.IData Data
{
get
{
if (_baseData == null)
_baseData = new umbraco.cms.businesslogic.datatype.DefaultData(this);
return _baseData;
}
}
public override Guid Id
{
get { return new Guid(“71518B4E-B1A5-11DD-A22C-8AAA56D89593″); }
}
public override string DataTypeName
{
get { return “Char Limit Textarea”; }
}
public override umbraco.interfaces.IDataPrevalue PrevalueEditor
{
get
{
if (_prevalueeditor == null)
_prevalueeditor = new charLimitPrevalueEditor(this);
return _prevalueeditor;
}
}
}
}
This is basicly where you give the datatype it’s name and unique id. The name will show up in the rendercontrol dropdown of the edit datatype page.
Each datatype needs to have a guid, when creating a new datatype make sure you change this to a unique one.
Next is the charLimitPrevalueEditor.cs file
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using umbraco.DataLayer;
using umbraco.BusinessLogic;
using umbraco.editorControls;
namespace Nibble.Umb.Datatypes.CharLimit
{
public class charLimitPrevalueEditor : System.Web.UI.WebControls.PlaceHolder, umbraco.interfaces.IDataPrevalue
{
#region IDataPrevalue Members
// referenced datatype
private umbraco.cms.businesslogic.datatype.BaseDataType _datatype;
private TextBox _txtLimit;
public charLimitPrevalueEditor(umbraco.cms.businesslogic.datatype.BaseDataType DataType)
{
_datatype = DataType;
setupChildControls();
}
private void setupChildControls()
{
_txtLimit = new TextBox();
_txtLimit.ID = “txtLimit”;
_txtLimit.CssClass = “umbEditorTextField”;
Controls.Add(_txtLimit);
}
public Control Editor
{
get
{
return this;
}
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
if (!Page.IsPostBack)
{
if (Configuration.Length > 0)
{
_txtLimit.Text = Configuration;
}
else
{
_txtLimit.Text = “100″;
}
}
}
public void Save()
{
_datatype.DBType = (umbraco.cms.businesslogic.datatype.DBTypes)Enum.Parse(typeof(umbraco.cms.businesslogic.datatype.DBTypes), DBTypes.Ntext.ToString(), true);
string data = _txtLimit.Text;
SqlHelper.ExecuteNonQuery(“delete from cmsDataTypePreValues where datatypenodeid = @dtdefid”,
SqlHelper.CreateParameter(“@dtdefid”, _datatype.DataTypeDefinitionId));
SqlHelper.ExecuteNonQuery(“insert into cmsDataTypePreValues (datatypenodeid,[value],sortorder,alias) values (@dtdefid,@value,0,”)”,
SqlHelper.CreateParameter(“@dtdefid”, _datatype.DataTypeDefinitionId), SqlHelper.CreateParameter(“@value”, data));
}
protected override void Render(HtmlTextWriter writer)
{
writer.WriteLine(“<table>”);
writer.Write(“<tr><th>Character Limit:</th><td>”);
_txtLimit.RenderControl(writer);
writer.Write(“</td></tr>”);
writer.Write(“</table>”);
}
public string Configuration
{
get
{
object conf =
SqlHelper.ExecuteScalar<object>(“select value from cmsDataTypePreValues where datatypenodeid = @datatypenodeid”,
SqlHelper.CreateParameter(“@datatypenodeid”, _datatype.DataTypeDefinitionId));
if (conf != null)
return conf.ToString();
else
return “”;
}
}
#endregion
public static ISqlHelper SqlHelper
{
get
{
return Application.SqlHelper;
}
}
}
}
This class is used to setup the datatype settings (something you can’t do when using the wrapper method). In this case it shows a textbox wich will be used to set the character limit. On save it will store this value (using the datalayer) in the database.
Last one is charLimitDataEditor.cs
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using umbraco.interfaces;
namespace Nibble.Umb.Datatypes.CharLimit
{
public class charLimitDataEditor : System.Web.UI.UpdatePanel, umbraco.interfaces.IDataEditor
{
private umbraco.interfaces.IData _data;
private string CharLimit;
private TextBox txtCharLimit;
private Label lblLimitInfo;
public charLimitDataEditor(umbraco.interfaces.IData Data, string Configuration)
{
_data = Data;
if (Configuration.Length > 0)
{
CharLimit = Configuration;
}
else
{
CharLimit = “100″;
}
}
public virtual bool TreatAsRichTextEditor
{
get { return false; }
}
public bool ShowLabel
{
get { return true; }
}
public Control Editor { get { return this; } }
public void Save()
{
this._data.Value = txtCharLimit.Text;
}
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
txtCharLimit = new TextBox();
txtCharLimit.Text = _data.Value.ToString();
txtCharLimit.TextMode = TextBoxMode.MultiLine;
txtCharLimit.Rows = 10;
txtCharLimit.Columns = 40;
txtCharLimit.CssClass = “umbEditorTextFieldMultiple”;
txtCharLimit.Attributes.Add(“onkeyup”, string.Format(“limitChars(this, {1}, ‘{0}’)”, “charlimitstatus” + base.ClientID, CharLimit));
lblLimitInfo = new Label();
lblLimitInfo.Attributes.Add(“id”, “charlimitstatus” + base.ClientID);
base.ContentTemplateContainer.Controls.Add(txtCharLimit);
base.ContentTemplateContainer.Controls.Add(new LiteralControl(“<br/>”));
base.ContentTemplateContainer.Controls.Add(lblLimitInfo);
string functionlimit = “function limitChars(textarea, limit, infodiv)”;
functionlimit += “{”;
functionlimit += “var text = textarea.value;”;
functionlimit += “var textlength = text.length;”;
functionlimit += “var info = document.getElementById(infodiv);”;
functionlimit += “if(textlength > limit)”;
functionlimit += “{”;
functionlimit += “info.innerHTML = ‘You cannot write more then ‘+limit+’ characters!’;”;
functionlimit += “textarea.value = text.substr(0,limit);”;
functionlimit += “return false;”;
functionlimit += “}”;
functionlimit += “else”;
functionlimit += “{”;
functionlimit += “info.innerHTML = ‘You have ‘+ (limit - textlength) +’ characters left.’;”;
functionlimit += “return true;”;
functionlimit += “}”;
functionlimit += “}”;
ScriptManager.RegisterClientScriptBlock(this.Page, this.GetType(), “limitChars”, functionlimit, true);
}
}
}
This one is used for the actual datatype dataeditor, so the control you will get in the content section of umbraco.
This class inherits from the updatepanel class and implements the umbraco.interfaces.IDataEditor. So on init you need to add the controls, in this case a textbox and a literal (for the info text on character limit) and fetch the saved data. And in the save method you can set what value needs to be saved.
Feel free to experiment with the sourcecode.