Creating custom umbraco datatypes
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.
Download sourcecode
This is really helpfull!
I ran into some troubles when I tried this myself, but this will definatelly get me further.
Keep em coming
PeterD
Another great idea for a next Benelux umbraco meetup
Neat, nice package. Thanks for sharing online.
/Dirk
Great article! Very good reference on how to implement a “true” datatype.
Will this datatype work on all database types (with V4) ?
@Morton, yep should work on all database types
Hey Tim,
Great walk though on how to do this. Maybe your next posting could cover how to use dictionary for your usercontrols.
Kindly,
Jesper
Yeah, Tim’s code is a good example of compatibility with all databases by using the data layer.
It’s a great tutorial. It should feature on the Umbraco books section, once that part of the Umbraco site got a cleanup.
Good job!
Thanks for the info, works great!
Hey Tim
Lovely implementation!
I’ve build the control in VS 2008 and referenced .net 3.5 ajax extensions - is that the reason why i get an error stating that scriptmanager is missing when i want to use the data type on a content page?
Thx
Ole
That was the problem.. Remeber to reference System.web.extensions version 1.x
Hi Tim,
Thanks for sharing this. Very usefull since I have to create my first datatype today.
Thanks,
Richard
I found your site on google and read a few of your other posts. Keep up the good work.
Thanks for this sharing.
But, does it work on V3?
And could you describe how to include it into Umbraco : including the dll into the bin folder isn’t enough…
thanks,
Jerome
Alright I used your code to make an Image Label set up that you give a URL in the prevalue area and instead of a normal text label you get an image to display on the admin side.
The only problem is I don’t know what to do after I made all the edits to the the code that you supply here. It doesn’t say anything about importing as a package or saving a file somewhere or editing a database properly. It just sort of cuts out? What is next?
@Mike, simply drop the assembly in the bin directory and then create a new datatype in the developer section, there you should be able to choose the new datatype as rendercontrol.
Thanks for this. But having to override the interface is crazy!
umbraco.cms.businesslogic.datatype.BaseDataType is an abstract base that has all the properties required to implement IDataType but does not actually implement IDataType, which I found quite confusing until I checked the definitions.
Here is a discussion: http://stackoverflow.com/questions/1395298/c-abstract-class-implements-interface-bad-coding-practice
IDataType is therefore “implemented” by the base, so if we want to provide our own implementation, which we do, we have to override the interface member.
I imagine there are “deep” reasons in the umbraco source that forced it to be this way
I know this post is over 3 years old, but the information is still relevant. Thank you for this post it helped a lot.
Carl
Thanks for the post. It was very helpful.
I have one quick question for you that I was unable to figure out.
Is it possible to obtain the cmsPropertyType id for the Editor? If so, that would be very very helpful.
I tried accessing _data.PropertyId but the get accessor is not implemented.
Is there another way around this to obtain the property id?
Thanks
My question is How can we add this individual umbraco project.package to umbraco cms project ?
Sorry if its very basic question.
Jim
need to add a persian (shamsi) date time picker in my website.i know about persian data time picker in Asp.net or C# but i’m using umbraco and need to add persiandatetimepicker in umbraco that can use and change persiandatetimepickers code in my code.your blog is exactly useful i start work with umbraco recently so i don’t know how to added this item into my umbraco project.
I successfully created two custom data types, but they’re being saved on the database as nText and I need to save them as nVarchar. How do I set this? can’t seem to find how.
Thanks in advance,
Amhed-
If you are going for finest contents like I do, simply pay a quick
visit this web page daily for the reason that it presents feature contents, thanks