Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • Jon Russell 7 posts 27 karma points
    Apr 09, 2011 @ 01:50
    Jon Russell
    0

    Creating a complex custom datatype

    I am trying to write my first custom datatype using the 'three class method' - inspired very heavily by Tim and Ove - and I have run  into a brick wall...

    Requirement : To store an array of values in a single field as parseable XML. I think the actual datatype works fine, shown in the class 'ClassTimeDatatype' below. It's rendering fine in the editor, and when I enter the first row of data and save, the values are persisted to the database. However, when I navigate back to that node in the CMS, the values are not coming back out of the database. I'm sure I'm missing something simple but I cant see what!

    If someone who knows what they are doing could glance over this so see what I am missing it would be so useful.

    /* Credits:
     *
     * Example Code and Setup:
     * Tim Geyssens (http://www.nibble.be)
     *
     * Template and Documentation:
     * Ove Andersen (http://www.eyecatch.no)
     *
    */
    using System;
    using umbraco.cms.businesslogic.datatype;

    namespace ClassTimeDatatype
    {
        public class DataType : AbstractDataEditor
        {
            private PrevalueEditor _prevalueeditor;

            private ClassTimeDatatype _control = new ClassTimeDatatype();

            public DataType()
            {
                base.RenderControl = _control;
                _control.Init += new EventHandler(ControlInit);
                base.DataEditorControl.OnSave += DataEditorControl_OnSave;
               
            }

            public void ControlInit(object sender, EventArgs e)
            {
                _control.LoadDataValue(base.Data.Value);
            }

            public override Guid Id
            {
                get
                {
                    return new Guid("68572280-7b8e-49ab-aa74-d2291f29f954");
                }
            }

            public override string DataTypeName
            {
                get
                {
                    return "Class Times";
                }
            }

            public override umbraco.interfaces.IDataPrevalue PrevalueEditor
            {
                get
                {
                    if (_prevalueeditor == null)
                    {
                        _prevalueeditor = new PrevalueEditor(this);
                    }
                    return _prevalueeditor;
                }
            }

            void DataEditorControl_OnSave(EventArgs e)
            {
                base.Data.Value = _control.GetDataValue();
                _control.LoadDataValue(base.Data.Value);

            }
        }
    }

     

    using System;
    using System.Web.UI.WebControls;
    using System.Collections.Generic;

    using System.Linq;
    using System.Xml;
    using System.Text;

    namespace ClassTimeDatatype
    {
        public class ClassTimeDatatype : Panel
        {

            // Datatype Controls

            private List<TextBox> _txtDateBegin;
            private List<TextBox> _txtDateEnd;

            private List<CheckBoxList> _chkRoomList;
            private List<CheckBoxList> _chkWeekdayList;
            private List<TextBox> _txtStartTime;
            private List<TextBox> _txtFinishTime;

            private List<ListItem> roomsTemplate;
            private List<ListItem> weekdaysTemplate;

            private object _dataValue;

            protected override void OnInit(EventArgs e)
            {
               
                roomsTemplate = new List<ListItem>();

                roomsTemplate.Add(new ListItem("Studio 1", "Studio 1"));
                roomsTemplate.Add(new ListItem("Studio 2", "Studio 2"));
                roomsTemplate.Add(new ListItem("Studio 3", "Studio 3"));

                weekdaysTemplate = new List<ListItem>();

                weekdaysTemplate.Add(new ListItem("Monday", "Monday"));
                weekdaysTemplate.Add(new ListItem("Tuesday", "Tuesday"));
                weekdaysTemplate.Add(new ListItem("Wednesday", "Wednesday"));
                weekdaysTemplate.Add(new ListItem("Thursday", "Thursday"));
                weekdaysTemplate.Add(new ListItem("Friday", "Friday"));
                weekdaysTemplate.Add(new ListItem("Saturday", "Saturday"));
                weekdaysTemplate.Add(new ListItem("Sunday", "Sunday"));

                base.OnInit(e);

            }

            internal void LoadDataValue(object dataValue)
            {
                try
                {
                    this.Controls.Clear();

                    _txtDateBegin = new List<TextBox>();
                    _txtDateEnd = new List<TextBox>();
                    _chkRoomList = new List<CheckBoxList>();
                    _chkWeekdayList = new List<CheckBoxList>();
                    _txtStartTime = new List<TextBox>();
                    _txtFinishTime = new List<TextBox>();

                    _dataValue = dataValue;

                    //Takes database value and configes current controls
                    if (dataValue != null)
                    {
                        XmlDocument retDoc = new XmlDocument();
                        retDoc.LoadXml(dataValue.ToString());

                        foreach (XmlNode node in retDoc.SelectNodes("//ClassTime"))
                        {
                            addControlRow(node);
                        }
                    }
                }
                catch
                {
                }
                finally
                {
                    addControlRow();
                }
            }

            internal object GetDataValue()
            {
                //Returns value from currently loaded controls for saving to database

                StringBuilder sb = new StringBuilder();

                sb.Append("<ClassTimes>");
                for (int i = 0; i < _txtDateBegin.Count; i++)
                {
                    if (!string.IsNullOrEmpty(_txtDateBegin[i].Text) || !string.IsNullOrEmpty(_txtDateEnd[i].Text) || !string.IsNullOrEmpty(getCheckBoxes(_chkRoomList[i])) || !string.IsNullOrEmpty(getCheckBoxes(_chkWeekdayList[i])) || !string.IsNullOrEmpty(_txtStartTime[i].Text) || !string.IsNullOrEmpty(_txtFinishTime[i].Text))
                    sb.AppendFormat("<ClassTime dateBegin=\"{0}\" dateEnd=\"{1}\" room=\"{2}\" weekDay=\"{3}\" startTime=\"{4}\" finishTime=\"{5}\"/>", _txtDateBegin[i].Text, _txtDateEnd[i].Text, getCheckBoxes(_chkRoomList[i]), getCheckBoxes(_chkWeekdayList[i]), _txtStartTime[i].Text, _txtFinishTime[i].Text);
                }
                sb.Append("</ClassTimes>");

                return sb.ToString();
            }


            protected override void Render(System.Web.UI.HtmlTextWriter writer)
            {
                // (Prints out the prevalue editor control)

                writer.WriteLine("<table>");
              
                writer.Write("<tr>");
                writer.Write("<th>Date Begin (yyyy-mm-dd)</th>");
                writer.Write("<th>Date End (yyyy-mm-dd)</th>");
                writer.Write("<th>Rooms</th>");
                writer.Write("<th>Weekdays</th>");
                writer.Write("<th>Start Time (hh:mm)</th>");
                writer.Write("<th>End Time (hh:mm)</th>");
                writer.Write("</tr>");

                for (int i = 0; i < _txtDateBegin.Count; i++)
                {
                    writer.Write("<tr>");
                    writer.Write("<th>"); _txtDateBegin[i].RenderControl(writer); writer.Write("</th>");
                    writer.Write("<th>"); _txtDateEnd[i].RenderControl(writer); writer.Write("</th>");
                    writer.Write("<th>"); _chkRoomList[i].RenderControl(writer); writer.Write("</th>");
                    writer.Write("<th>"); _chkWeekdayList[i].RenderControl(writer); writer.Write("</th>");
                    writer.Write("<th>"); _txtStartTime[i].RenderControl(writer); writer.Write("</th>");
                    writer.Write("<th>"); _txtFinishTime[i].RenderControl(writer); writer.Write("</th>");
                    writer.Write("</tr>");
                }

                writer.Write("</table>");
               
            }

            private void addControlRow()
            {

                int count = _txtDateBegin.Count;

                TextBox txtDateBegin = new TextBox();
                txtDateBegin.ID = string.Format("txtDateBegin_{0}", count);
                txtDateBegin.CssClass = "umbDateTimePicker";
                _txtDateBegin.Add(txtDateBegin);
                Controls.Add(txtDateBegin);

                TextBox txtDateEnd = new TextBox();
                txtDateEnd.ID = string.Format("txtDateEnd_{0}", count);
                txtDateEnd.CssClass = "umbDateTimePicker";
               
                _txtDateEnd.Add(txtDateEnd);
                Controls.Add(txtDateEnd);

                CheckBoxList chkRoomList = new CheckBoxList();
                chkRoomList.ID = string.Format("chkRoomList_{0}", count);
                chkRoomList.Items.AddRange(roomsTemplate.ToArray());

                _chkRoomList.Add(chkRoomList);
                Controls.Add(chkRoomList);

                CheckBoxList chkWeekdayList = new CheckBoxList();
                chkWeekdayList.ID = string.Format("chkWeekdayList_{0}", count);
                chkWeekdayList.Items.AddRange(weekdaysTemplate.ToArray());

                _chkWeekdayList.Add(chkWeekdayList);
                Controls.Add(chkWeekdayList);

                TextBox txtStartTime = new TextBox();
                txtStartTime.ID = string.Format("txtStartTime_{0}", count);

                _txtStartTime.Add(txtStartTime);
                Controls.Add(txtStartTime);

                TextBox txtFinishTime = new TextBox();
                txtFinishTime.ID = string.Format("txtFinishTime_{0}", count);

                _txtFinishTime.Add(txtFinishTime);
                Controls.Add(txtFinishTime);

            }

            private void addControlRow(XmlNode node)
            {

                int count = _txtDateBegin.Count;

                TextBox txtDateBegin = new TextBox();
                txtDateBegin.ID = string.Format("txtDateBegin_{0}", count);
                txtDateBegin.Text = node.Attributes["dateStart"].Value;
                _txtDateBegin.Add(txtDateBegin);
                Controls.Add(txtDateBegin);

                TextBox txtDateEnd = new TextBox();
                txtDateEnd.ID = string.Format("txtDateEnd_{0}", count);
                txtDateEnd.Text = node.Attributes["dateEnd"].Value;
                _txtDateEnd.Add(txtDateEnd);
                Controls.Add(txtDateEnd);

                CheckBoxList chkRoomList = new CheckBoxList();
                chkRoomList.ID = string.Format("chkRoomList_{0}", count);
                chkRoomList.Items.AddRange(roomsTemplate.ToArray());
                selectCheckBoxes(chkRoomList, node.Attributes["room"].Value);
                _chkRoomList.Add(chkRoomList);
                Controls.Add(chkRoomList);

                CheckBoxList chkWeekdayList = new CheckBoxList();
                chkWeekdayList.ID = string.Format("chkWeekdayList_{0}", count);
                chkWeekdayList.Items.AddRange(weekdaysTemplate.ToArray());
                selectCheckBoxes(chkWeekdayList, node.Attributes["weekday"].Value);
                _chkWeekdayList.Add(chkWeekdayList);
                Controls.Add(chkWeekdayList);

                TextBox txtStartTime = new TextBox();
                txtStartTime.ID = string.Format("txtStartTime_{0}", count);
                txtStartTime.Text = node.Attributes["startTime"].Value;
                _txtStartTime.Add(txtStartTime);
                Controls.Add(txtStartTime);

                TextBox txtFinishTime = new TextBox();
                txtFinishTime.ID = string.Format("txtFinishTime_{0}", count);
                txtFinishTime.Text = node.Attributes["finishTime"].Value;
                _txtFinishTime.Add(txtFinishTime);
                Controls.Add(txtFinishTime);

            }

            private string getCheckBoxes(CheckBoxList checkBoxList)
            {
                StringBuilder sb = new StringBuilder();

                foreach (ListItem item in checkBoxList.Items)
                {
                    if (item.Selected) sb.AppendFormat("{0},", item.Value);
                }

                return sb.ToString();
            }

            private void selectCheckBoxes(CheckBoxList checkBoxList, string fieldValue)
            {
                string[] valueList = fieldValue.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);

                foreach (ListItem item in checkBoxList.Items)
                {
                    item.Selected = valueList.Contains(item.Value);
                }

            }

        }
    }

    using System;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using umbraco.BusinessLogic;
    using umbraco.cms.businesslogic.datatype;
    using umbraco.DataLayer;
    using umbraco.interfaces;
    using System.Collections.Generic;
    using System.Xml;
    using System.Text;

    using System.Linq;

    namespace ClassTimeDatatype
    {
        public class PrevalueEditor : PlaceHolder, IDataPrevalue
        {
            #region IDataPrevalue Members

            // Referenced datatype
            private readonly BaseDataType _datatype;

            public PrevalueEditor(DataType dataType)
            {
                _datatype = dataType;
                SetupChildControls();
            }

            private void SetupChildControls()
            {
            }

            public Control Editor
            {
                get
                {
                    return this;
                }
            }

            protected override void OnLoad(EventArgs e)
            {
                base.OnLoad(e);
            }

            public void Save()
            {
                _datatype.DBType = (DBTypes)Enum.Parse(typeof(DBTypes), DBTypes.Ntext.ToString(), true);
                SqlHelper.ExecuteNonQuery("delete from cmsDataTypePreValues where datatypenodeid = @dtdefid", SqlHelper.CreateParameter("@dtdefid", _datatype.DataTypeDefinitionId));
            }

            protected override void Render(HtmlTextWriter writer)
            {
                base.Render(writer);
            }

            #endregion

            public static ISqlHelper SqlHelper
            {
                get
                {
                    return Application.SqlHelper;
                }
            }

        }
    }

  • Daniel Bardi 927 posts 2562 karma points
    Apr 09, 2011 @ 08:41
    Daniel Bardi
    0

    This should help you: http://www.nibble.be/?p=51

  • Jon Russell 7 posts 27 karma points
    Apr 09, 2011 @ 10:46
    Jon Russell
    0

    Thanks Daniel -

    However, I kind of thought that article (Nov 2008) is now slightly outdated. On 4.6 (?) or above, Umbraco recognises that you are trying to store XML data and no longer automatically wraps it in CDATA. My data is indeed being saved correctly to the database and is parseable via an XSL macro. However, it is not being retrieved properly in the CMS editor to make amendments or add new data - and just comes up blank.

    Does that make sense?

  • Ove Andersen 435 posts 1541 karma points c-trib
    Apr 11, 2011 @ 09:44
    Ove Andersen
    0

    Is base.Data.Value empty when you load the control?

    If it helps, here is (almost) what I do in DataType Grid in uComponents:

     

    private IList<MyObject> GetStoredValues() {
    
        var list = new List<MyObject>();
    
        var doc = new XmlDocument();
        doc.LoadXml(Data.Value.ToString());
    
        // Create and add XML declaration. 
        XmlDeclaration xmldecl = doc.CreateXmlDeclaration("1.0", null, null);
        XmlElement root = doc.DocumentElement;
        doc.InsertBefore(xmldecl, root);
    
        // Get stored values from database
        if (root.ChildNodes.Count > 0)
        {
            foreach (XmlNode container in root.ChildNodes)
            {
                // Add the node values to a list
                var m = new MyObject() 
                        {
                  Id = int.Parse(container.Attributes["id"].Value),
                            Value = container.ChildNodes[0].InnerText // The first node
                        }
                list.Add(m);
            }
        }
    
        return list;
    }

     

  • Comment author was deleted

    Apr 11, 2011 @ 09:47

    If you are running at least version 4.6 of umbraco I wouldn't touch the "3 class method" anymore and simply go for the usercontrol wrapper

    Since you can also have settings + xml properties using that

    Some details:

    http://www.nibble.be/?p=99

    http://www.nibble.be/?p=100

    http://stream.umbraco.org/video/1533917/tim-geyssens-master-of

Please Sign in or register to post replies

Write your reply to:

Draft