More in this section

Forums / General Discussions / Widget with a custom designer and string[] property

Widget with a custom designer and string[] property

3 posts, 0 answered
  1. Vyacheslav
    Vyacheslav avatar
    11 posts
    Registered:
    18 Nov 2010
    24 Mar 2011
    Link to this post
    Hi.
    How can I manage widget string[] property by a custom designer? I've tried to do following:

    Widget:
    [Telerik.Sitefinity.Web.UI.ControlDesign.ControlDesigner(typeof(TextControlDesigner))]
     public class TextControl : TextControlBase
     {
         private const string TemplateName = "Controls.Resources.Templates.TextControl.ascx";
         protected override void InitializeControls(GenericContainer container)
         {
             TextBox1.Text = this.Text;
             if (this.Test != null)
             {
                 TextBox2.Text = this.Test[0];
             }
         }
     
        public string Text { get; set; }
     
         public string[] Test { get; set; }
     
         protected override string LayoutTemplateName
         {
             get
             {
                 return TemplateName;
             }
         }
         protected virtual TextBox TextBox1
         {
             get
             {
                 return base.Container.GetControl<TextBox>("TextBox1", true);
             }
         }
         protected virtual TextBox TextBox2
         {
             get
             {
                 return base.Container.GetControl<TextBox>("TextBox2", true);
             }
         }
     }


    Widget's Template:
    <%@ Control Language="C#" %>
    <asp:TextBox runat="server" ID="TextBox1" />
    <asp:TextBox runat="server" ID="TextBox2" />

    Custom Designer:
    public class TextControlDesigner : ControlDesignerBase
       {
           private const string TemplateName = "Controls.Resources.Templates.TextControlDesigner.ascx";
           private const string ScriptReference = "Controls.Resources.JavaScript.TextControlDesigner.js";
           protected override void InitializeControls(GenericContainer container)
           {
               base.DesignerMode = ControlDesignerModes.Simple;
           }
     
           protected override string LayoutTemplateName
           {
               get
               {
                   return TemplateName;
               }
           }
           public override IEnumerable<System.Web.UI.ScriptReference> GetScriptReferences()
           {
               var res = new List<ScriptReference>(base.GetScriptReferences());
               var assemblyName = this.GetType().Assembly.GetName().ToString();
               res.Add(new ScriptReference(ScriptReference, assemblyName));
               return res.ToArray();
           }      
     
       }

    Control designer's template:
    <%@ Register Assembly="Telerik.Sitefinity" Namespace="Telerik.Sitefinity.Web.UI"
        TagPrefix="sitefinity" %>
    <%@ Register Assembly="Telerik.Web.UI" Namespace="Telerik.Web.UI" TagPrefix="telerik" %>
    <div class="sfContentViews">
        <div id="TextControlOptions">
            <h2>
                Fine tune your Text control
            </h2>
            <div>
                <label for="text">
                    Text</label>
                <input type="text" id="text" class="sfTxt" />
                <label for="test">
                    Text</label>
                <input type="text" id="test" class="sfTxt" />        
            </div>
        </div>
    </div>

    and custom designer's .js file:
    Type.registerNamespace("Controls.Navigation");
     
    Controls.Navigation.TextControlDesigner = function (element) {
       Controls.Navigation.TextControlDesigner.initializeBase(this, [element]);
        this._parentDesigner = null;
        this._googleAnalyticsCodeTextField = null;
        this._scriptEmbedPositionChoiceField = null;
        this._toogleGroupSettingsDelegate = null;
    }
     
     
    Controls.Navigation.TextControlDesigner.prototype = {
        initialize: function () {
            this.refreshUI();
            Controls.Navigation.TextControlDesigner.callBaseMethod(this, 'initialize');
            this._toogleGroupSettingsDelegate = Function.createDelegate(this, function () {
                dialogBase.resizeToContent();
            })
        },
        dispose: function () {
           Controls.Navigation.TextControlDesigner.callBaseMethod(this, 'dispose');
        },
        refreshUI: function () {
            var data = this._propertyEditor.get_control();
            jQuery("#text").val(data.Text);
            if ((data.Test !== null) && (typeof (data.Test) !== 'undefined')) {
                jQuery("#test").val(data.Test[0]);
            }
        },
        applyChanges: function () {
     
            var controlData = this._propertyEditor.get_control();
            controlData.Text = jQuery("#text").val();
            controlData.Test = new Array();
            controlData.Test[0] = '1';
        }
    }
    Controls.Navigation.TextControlDesigner.registerClass('Controls.Navigation.TextControlDesigner', Telerik.Sitefinity.Web.UI.ControlDesign.ControlDesignerBase);
    if (typeof (Sys) !== 'undefined') Sys.Application.notifyScriptLoaded();
    * I've removed the assembly name from a code.

    When I had only a string Text property, I was able to save it by pressing a Save button. But when I added the string[] Test property every attempt to save is finished by following message at Firebug's console:

    Error Status Code: 'InternalServerError'
     
    Details: There was an error deserializing the object of type Telerik.Sitefinity.Modules.Pages.Web.Services.Model.WcfControlProperty[]. End element 'PropertyValue' from namespace '' expected. Found element 'item' from namespace ''.
  2. Ivan Dimitrov
    Ivan Dimitrov avatar
    16072 posts
    Registered:
    12 Sep 2017
    28 Mar 2011
    Link to this post
    Hi Vyacheslav,

    Generally you should deserialize and serialize the object on the client using  Sys.Serialization.JavaScriptSerializer

    All the best,
    Ivan Dimitrov
    the Telerik team
  3. Vyacheslav
    Vyacheslav avatar
    11 posts
    Registered:
    18 Nov 2010
    30 Mar 2011
    Link to this post
    Hi Ivan,
    Thank you for your answer.
    I've tried to do following at the designer's js code:

    applyChanges: function () {
          var controlData = this._propertyEditor.get_control();
          controlData.Text = jQuery("#text").val();
          var test = new Array();
          test[0] = '1';
          test[1] = '2';
          console.log("test: %o", test);
          controlData.Test = Sys.Serialization.JavaScriptSerializer.serialize(test);
          console.log("serialized test: %o", Sys.Serialization.JavaScriptSerializer.serialize(test));
      }

    Also, I've added the [TypeConverter(typeof(StringArrayConverter))] attribute of the TextControl.Test property and saving is working properly now. My widget base class:

    namespace HEH.WebSite.EducationalPortal.Controls.ControlBase
    {
        using System.ComponentModel;
        using Converters;
        using Telerik.Sitefinity.Web.UI;


        public abstract class TextControlBase : SimpleView
        {
            public string Text { get; set; }


            [TypeConverter(typeof(StringArrayConverter))]
            public string[] Test { get; set; }
        }
    }

    StringArrayConverter:
    Controls.Converters
    {
        using System;
        using System.ComponentModel;
        using System.ComponentModel.Design.Serialization;
        using System.Globalization;
        using Newtonsoft.Json;
     
        public class StringArrayConverter : TypeConverter
        {
            public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
            {
                return ((sourceType == typeof(string)) || base.CanConvertFrom(context, sourceType));
            }
     
            public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
            {
                return ((destinationType == typeof(InstanceDescriptor)) || base.CanConvertTo(context, destinationType));
            }
     
            public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
            {
                if (value is string)
                {
                    return JsonConvert.DeserializeObject<string[]>(value as string);
                }
                return base.ConvertFrom(context, culture, value);
            }
     
            public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value,
                                             Type destinationType)
            {
                if (value is string[])
                {
                    return JsonConvert.SerializeObject(value);
                }
                return base.ConvertTo(context, culture, value, destinationType);
            }
        }
    }

    Thank you for your help.
3 posts, 0 answered