Nibble

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.

customdatatype

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.

customdatatype2

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.

customdatatypes3

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.

customdatatypes4

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

22 Comments so far

  1. PeterD on November 18th, 2008

    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

  2. DIrk on November 18th, 2008

    Another great idea for a next Benelux umbraco meetup ;)
    Neat, nice package. Thanks for sharing online.

    /Dirk

  3. Morten Bock on November 18th, 2008

    Great article! Very good reference on how to implement a “true” datatype.

    Will this datatype work on all database types (with V4) ?

  4. Tim Geyssens on November 18th, 2008

    @Morton, yep should work on all database types

  5. Jesper Ordrup on November 18th, 2008

    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

  6. Ruben Verborgh on November 18th, 2008

    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!

  7. Grigory Rozorf on January 17th, 2009

    Thanks for the info, works great!

  8. Ole Mansfeld on January 18th, 2009

    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

  9. Ole Mansfeld on January 18th, 2009

    That was the problem.. Remeber to reference System.web.extensions version 1.x

  10. richard on January 28th, 2009

    Hi Tim,

    Thanks for sharing this. Very usefull since I have to create my first datatype today.

    Thanks,

    Richard

  11. Gilia on February 7th, 2009

    I found your site on google and read a few of your other posts. Keep up the good work.

  12. Jerome on March 11th, 2009

    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

  13. Mike on March 31st, 2010

    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?

  14. Tim Geyssens on April 1st, 2010

    @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.

  15. ben on May 6th, 2010

    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 :)

  16. Carl B. Johnson on February 7th, 2011

    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

  17. Zac on June 22nd, 2011

    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

  18. Jim on August 17th, 2011

    My question is How can we add this individual umbraco project.package to umbraco cms project ?

    Sorry if its very basic question.

    Jim

  19. amin on November 18th, 2012

    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.

  20. Amhed Herrera on December 15th, 2012

    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-

  21. dofus kamas gratuit on January 30th, 2014

    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

  22. pharmacy tech on May 25th, 2014

    Why people still make use of to read news
    papers when in this technological globe everything is accessible on net?

Leave a Reply