+1-888-365-2779
Try Now
More in this section

Forums / Developing with Sitefinity / Custom Control Property Not Persisted to DB

Custom Control Property Not Persisted to DB

5 posts, 0 answered
  1. JD
    JD avatar
    5 posts
    Registered:
    04 Oct 2010
    20 Oct 2010
    Link to this post
    I've written a custom control that wraps GenericContent, inherits from a customized base control and have added a couple of custom properties.  It's actually kind of a hybrid control which can either be added to a page via the control toolbox in Page Admin or can be added via markup to a page using templates.  That should't be relevant though I included it just in case it is.

    The problem I'm having is that the additional properties are not being persisted to the database.  Here is a concatenated version of my code:

    public abstract class CustomBaseControl : CompositeControl
    {
        private MyConfig m_Config;
        ///<summary>
        ///Exposes a custom config object
        ///</summary>
        [Browsable(false)]
        protected MyConfig Config
        {
            get { return m_Config; }
        }
    }
      
    [ControlDesignerAttribute(
        "Telerik.Cms.Engine.WebControls.Design.GenericContentDesigner, Telerik.Cms.Engine")] 
    public sealed class CustomGenericContent 
        : CustomBaseControl, INamingContainer, IGenericContent
    {
        private string m_Property;
        private ITemplate m_ContentTemp;
        private GenericContent m_GenContent;
        public CustomGenericContent()
        {
            m_GenContent = new GenericContent();
        }
        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);
        }
        [Browsable(true),
        CmsBrowsable(false),
        CmsPersistable(true)]
        public string CustomProperty
        {
            get { return m_Property; }
            set { m_Property = value; }
        }
        #region Template support
        [PersistenceMode(PersistenceMode.InnerProperty), 
        TemplateContainer(typeof(PlaceHolder)),
        CmsBrowsable(false)]
        public ITemplate ContentTemplate
        {
            get { return m_ContentTemp; }
            set { m_ContentTemp = value; }
        }
        protected override void CreateChildControls()
        {
            if (m_ContentTemp != null)
            {
                this.Controls.Clear();
                PlaceHolder phContent = new PlaceHolder();
                m_ContentTemp.InstantiateIn(phContent);
                this.Controls.Add(phContent);
            }
            else
            {
                this.Controls.Add(m_GenContent);
                base.CreateChildControls();
            }
        }
        #endregion
        #region Wrap GenericContent Members
          
        [CmsBrowsable(false)]
        [CmsPersistable(true)]
        public string Content
        {
            get { return m_GenContent.Content; }
            set { m_GenContent.Content = value; }
        }
          
        [Browsable(false)]
        public Guid ContentID
        {
            get { return m_GenContent.ContentID; }
            set { m_GenContent.ContentID = value; }
        }
        [Browsable(false)]
        public string ProviderName
        {
            get { return m_GenContent.ProviderName; }
            set { m_GenContent.ProviderName = value; }
        }
        [Browsable(false)]
        public IContent SharedContent
        {
            get { return this.m_GenContent.SharedContent; }
        }
        [Browsable(false)]
        public bool UseStagedVersion
        {
            get { return m_GenContent.UseStagedVersion; }
            set { m_GenContent.UseStagedVersion = value; }
        }
        [CmsBrowsable(false), CmsPersistable(true)]
        public bool HasDynamicLinks
        {
            get { return m_GenContent.HasDynamicLinks; }
            set { m_GenContent.HasDynamicLinks = value; }
        }
        public string GetItemUrl(string provider, Guid id, bool resolveAsAbsoluteUrl)
        {
            return m_GenContent.GetItemUrl(provider, id, resolveAsAbsoluteUrl);
        }
        public void RenderBinaryContent(HtmlTextWriter writer)
        {
            m_GenContent.RenderBinaryContent(writer);
        }
        public void RenderTextContent(HtmlTextWriter writer)
        {
            m_GenContent.RenderTextContent(writer);
        }
        #endregion  
    }


    After dropping the control onto the page in Admin/Pages, I find the ControlID in sf_CmsCtrlLinks and query the sf_CmsControlProperty table for the ControlID.  The only properties stored there are: Content, Font, ID and Names.  Why isn't my CustomProperty being persisited to the database?
  2. JD
    JD avatar
    5 posts
    Registered:
    04 Oct 2010
    20 Oct 2010
    Link to this post
    Followup - Even stranger behavior...

    To continue testing my control, assuming the persistence issue will be resolved soon, I manually inserted the appropriate record to the sf_CmsControlProperty table for the CustomProperty.  When I view the page (and hence the control) in the admin site with either pages.aspx?select=pageId or default.aspx?cmspagemode=edit, debugger attached, the engine sets the control's CustomProperty as appropriate and I get the expected behavior.  When I view the live page, debugger attached, the set_CustomProperty() method is NEVER CALLED!

    The debugger does catch the calls to the set_ methods for the IGenericContent interface members but not to any of my custom properties.  Is it because I'm implementing IGenericContent and the engine handles that specifically?
  3. Radoslav Georgiev
    Radoslav Georgiev avatar
    3370 posts
    Registered:
    01 Feb 2016
    21 Oct 2010
    Link to this post
    Hi JD,

    Thank you for Contacting Telerik Support.

    Can you please try using the approach sampled in this KB article: How to wrap a Generic Content control in 3.6 SP1. You can find a sample control which uses this approach in the following blog post: How to wrap a Generic Content control in 3.6 SP1 Roles Selector and hiding control based on user's roles.

    Best wishes,
    Radoslav Georgiev
    the Telerik team
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
  4. JD
    JD avatar
    5 posts
    Registered:
    04 Oct 2010
    21 Oct 2010
    Link to this post
    I actually used that one and its related post to create the control.  After playing with it more, I figured out the root cause of my issue but still am not sure how to correct it.

    It appears that only properties set by the ControlEditor are being persisted.  I found that out when I manually changed the property in the editor and saw it was finally persisted to the DB.  My property actually has a "default" value that is based on the current context.  I apologize that my concatenated code didn't depict that.  Here is a better representation of what my CustomProperty actually looks like:

    public string CustomProperty
    {
        get 
        {
            // In theory, this should allow the default to be set 
            // when the control is created for the first time on a site.
            if (m_Property == null)
            {
                m_Property = base.Config.DefaultValue;
            }
            return m_Property;
        }
        set { m_Property = value; }
    }

    Unfortunately, the Config.DefaultValue result is based on call context (it will differ based on URL) and I only want to use this value one time, when the control is first placed onto a page in the admin site.  Every time thereafter, I need the value to have come from the database.

    How can I cause the engine to serialize this property without requiring content editors to input it manually? 
    Thanks in advance.

  5. Radoslav Georgiev
    Radoslav Georgiev avatar
    3370 posts
    Registered:
    01 Feb 2016
    22 Oct 2010
    Link to this post
    Hi JD,

    The problem is that the code from the article you are using relates to an older version of Sitefinity. This approach is no longer valid in Stiefinity 3.7 SP4.  On the other hand the blog post which I have linked uses the same approach for setting a property - it defines a default value in case it is not set:
    public string[] Roles
    {
        get
        {
            object obj = this.roles;
            if (obj == null)
                return new string[]{};
            return (string[])obj;
        }
        set
        {
            this.roles = value;
        }
    }


     You can also define a DevaultValue element just in the same way you define the Category element.

    Sincerely yours,
    Radoslav Georgiev
    the Telerik team
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
Register for webinar
5 posts, 0 answered