More in this section

Forums / Developing with Sitefinity / Control Designers

Control Designers

11 posts, 0 answered
  1. Gabe Sumner
    Gabe Sumner avatar
    440 posts
    Registered:
    09 Sep 2007
    04 Oct 2007
    Link to this post
    I've been reading the "Control Designer Setup" page in the "Developer Manual" for a few hours now.

    I'm afraid I don't get it. 

    I understand that I have to add a mapping in the "web.config" file.

    I understand that I need to create an "ascx" template.

    I don't understand how those <$Resources> tags get used or work.

    I don't understand how that "ascx" template can inherit from "ControlDesigner".

    I really don't understand any of the code that is shown or how it fits with the "ascx" template.

    Is there a full working example of all of this somewhere?   I feel like I'm looking at pieces of all of this but have no idea how it all fits together.

    Thanks,

    Gabe
    ===========
  2. Pepi
    Pepi avatar
    981 posts
    Registered:
    31 Jan 2017
    04 Oct 2007
    Link to this post
    Hi Gabe,

    Your feedback on this matter is highly appreciated. Our purpose is to make the documentation much more comprehensive and useful for the developers. So, thanks a lot for the detailed explanation of the weak points in this topic.

    You could find in the attachment the source code of ImageControlDesigner implementation.

    In fact, .ascx file is a template and represents a mix of HTML elements and ASP.NET controls that make up the layout for a particular control designer. In short, templates customize a control's user interface. The composite control for the given Control Designer loads the template describing its appearance as an external file with LoadTemplate method of Page class. The other possible approach for creating server control interface is to hard-code it in the code. For example:

    LinkButton lnkCreateNewList = new LinkButton(); 
    lnkCreateNewList.ID = "newListButton"
    lnkCreateNewList.Text = "Create New List"
    this.Controls.Add(lnkCreateNewList); 

    I want to clarify: 
    .ascx template doesn't inherit from ControlDesigner. ControlDesigner represents the base class for Sitefinity custom control designers and all custom property editors should inherit it.

    Resources provides access to the corresponding resource file and gets the value for the specified key. For example: <%$Resources:SelectImage%> gets the string value for SelectImage resource key.

    Hope this is helpful.

    Regards,
    Pepi
    the Telerik team

    Instantly find answers to your questions at the new Telerik Support Center
  3. Gabe Sumner
    Gabe Sumner avatar
    440 posts
    Registered:
    09 Sep 2007
    04 Oct 2007
    Link to this post
    Hi Pepi,

    Your post was a ton of help!  Although for learning purposes I nuked almost all of your code in order to get a (useless) "Hello world!" example going.  Here is what I came up with.

    First create I created an "ascx" file consisted of the following:

    <div class="ctrlProps">  
        <div class="ctrlContent">  
        <div class="ctrlContentImage">  
            <div class="ctrlContentImageColumn">  
                <p> 
                    Hello world!  
                </p>   
            </div>     
        </div> 
        </div> 
    </div> 

    Then I created the Control Designer code:

    using System;  
    using System.Collections.Generic;  
    using System.Text;  
    using System.Web.UI;  
    using Telerik.Cms.Web.UI;  
    using System.IO;  
    using Telerik.Framework.Web.Design;  
    using System.Web.UI.WebControls;  
    using System.ComponentModel;  
    using Telerik.Utilities.Reflection;  
    using System.Diagnostics;  
    using System.Web;  
     
    namespace MyExample  
    {  
        /// <summary> 
        /// Inherits ControlDesigner class and represents the control designer of Image web control.  
        /// </summary> 
        public class ExampleControlDesigner: Telerik.Framework.Web.Design.ControlDesigner  
        {  
            /// <summary> 
            /// Default constructor. Initializes a new instance of ImageControlDesigner class.  
            /// </summary> 
            public ExampleControlDesigner()  
            {  
            }  
     
            /// <summary> 
            /// Creates the child controls in ImageControlDesigner control.  
            /// </summary> 
            protected override void CreateChildControls()  
            {  
                this.Controls.Clear();  
     
                Container cnt = new Container();  
     
                string path = "~/ControlDesigners/ExampleControlDesigner.ascx";  
     
                ITemplate itemTemplate = this.Page.LoadTemplate(path);  
     
                itemTemplate.InstantiateIn(this);  
            }  
        }  
    }  
     

    Then I have to include the mapping in the "web.config" file:

    <add key="MyExample.ExampleControl" value="MyExample.ExampleControlDesigner, App_Code" /> 

    This all works.  A new "Basic" tab is created for the Control Designer and the wonderful words "Hello World" get printed.  Again, I know this isn't useful, but it's a start. 

    Thanks for your help,

    Gabe
    =================
  4. Gabe Sumner
    Gabe Sumner avatar
    440 posts
    Registered:
    09 Sep 2007
    04 Oct 2007
    Link to this post
    Resources provides access to the corresponding resource file and gets the value for the specified key. For example: <%$Resources:SelectImage%> gets the string value for SelectImage resource key.

    This I still don't understand.  In the example you provided their are essentially 2 files (the "ascx" template file and the Control Designer "cs" file).

    The ascx file makes mention of <%$Resources:SelectImage%>.

    "SelectImage" isn't mentioned anywhere in the corresponding "cs" file.  So what is the "corresponding resource file" that you refer to above?  I guess I don't understand where the "SelectImage" resource key comes from.

    Thanks again,

    Gabe
    ===============
  5. Gabe Sumner
    Gabe Sumner avatar
    440 posts
    Registered:
    09 Sep 2007
    05 Oct 2007
    Link to this post
    I have now gotten a very basic Control Designer working.  It has 1 RadioButtonList which is used to populate a "CssClass" property.

    Here is what I did for the "ascx" file:

    <div class="ctrlProps">  
        <div class="ctrlContent">  
            <p> 
                <asp:Label AssociatedControlID="CssClass" runat="server">Color</asp:Label>   
                <asp:RadioButtonList ID="CssClass" RepeatDirection="Horizontal" RepeatLayout="Flow" runat="server">  
                    <asp:ListItem Text="Gray" Value="gray" /> 
                    <asp:ListItem Text="Blue" Value="blue" /> 
                    <asp:ListItem Text="Green" Value="green" /> 
                </asp:RadioButtonList> 
            </p>   
        </div> 
    </div> 

    For the Control Designer "cs" file here is my code:

    using System;  
    using System.Collections.Generic;  
    using System.Text;  
    using System.Web.UI;  
    using Telerik.Cms.Web.UI;  
    using System.IO;  
    using Telerik.Framework.Web.Design;  
    using System.Web.UI.WebControls;  
    using System.ComponentModel;  
    using Telerik.Utilities.Reflection;  
    using System.Diagnostics;  
    using System.Web;  
     
    namespace MyExamples  
    {  
        /// <summary> 
        /// Inherits ControlDesigner class and represents the control designer of Image web control.  
        /// </summary> 
        public class BoxControlDesigner : Telerik.Framework.Web.Design.ControlDesigner  
        {  
            /// <summary> 
            /// Default constructor. Initializes a new instance of ImageControlDesigner class.  
            /// </summary> 
            public BoxControlDesigner()  
            {  
            }  
     
            /// <summary> 
            /// Creates the child controls in ImageControlDesigner control.  
            /// </summary> 
            protected override void CreateChildControls()  
            {  
                this.Controls.Clear();  
     
                string path = "~/ControlDesigners/BoxControlDesigner.ascx";  
                ITemplate itemTemplate = this.Page.LoadTemplate(path);  
                Control ourControl = new Control();  
                itemTemplate.InstantiateIn(this);  
     
                RadioButtonList rad_CssClass = (RadioButtonList)Controls[0].FindControl("CssClass");  
                rad_CssClass.SelectedIndexChanged += new EventHandler(CssClassChanged);  
            }  
     
            /// <summary> 
            ///   
            /// </summary> 
            /// <param name="sender"></param> 
            /// <param name="e"></param> 
            public void CssClassChanged(object sender, EventArgs e)  
            {  
                base.UpdateProperty(sender, base.DesignedControl);  
            }  
        }  
    }  
     

    This is still very simple, but it does appear to work.  Pepi your example looks awfully advanced.  It took me a lot of time to get it down to something basic that would run & work.  There is a lot of stuff going on in that code that I still don't understand.  For those learning, hopefully my code above might help a bit.

    P.S.  Whatever style-sheets get applied to these Control Designers makes RadioButtonLists look awful.  I still haven't pinned down where this is being caused.

    Gabe
    =================
  6. Sonya
    Sonya avatar
    231 posts
    Registered:
    24 Sep 2012
    05 Oct 2007
    Link to this post
    Hi Gabe,
     
    Thank you for writing us about designers. After your request we noticed that there was a problem with the Developers Manual and all code, such as <%$Resources:SelectImage%>, was actually displayed <$Resources>. We fixed it.
     
    As to your question : how does the .cs file link to the template:
    The .cs file should be placed in your module. The path of the .ascx file should be /<your_project>/Sitefinity/Admin/ControlTemplates/ControlEditors/
    and of the Resources file - /<your_project>/Sitefinity/Admin/ControlTemplates/ControlEditors/App_LocalResources/

    For .cs to access the template, the path of the template should be specified. See how this is done in the following code, which is one of the properties of the ImageControlDesigner.cs class:

    public string ItemTemplatePath 
            { 
                get 
                { 
                    string value = (string)this.ViewState["ItemTemplatePath"]; 
                    return String.IsNullOrEmpty(value) ? "~/Sitefinity/Admin/ControlTemplates/ControlEditors/ImageControlDesigner.ascx" : value; 
                } 
                set 
                { 
                    this.ViewState["ItemTemplatePath"] = value; 
                } 
            } 

    As was stated in the prevous post, the template, on the other hand, accesses the resource file by a key, such as <%$Resources:AlternativeText%>, where AlternativeText is the key. In order for the control designer to be re-usable, there could be different templates  which it would access. Therefore, there is no direct relation between the resource file and the .cs class: the relation is between the .cs and the template.

    Hope this sheds some light.

    Sincerely yours,
    Sonya
    the Telerik team

    Instantly find answers to your questions at the new Telerik Support Center
  7. Gabe Sumner
    Gabe Sumner avatar
    440 posts
    Registered:
    09 Sep 2007
    09 Oct 2007
    Link to this post
    P.S.  Whatever style-sheets get applied to these Control Designers makes RadioButtonLists look awful.  I still haven't pinned down where this is being caused.

    Regarding my comment above, I haven't been able to find a way around this.

    The RadioButtonList tag seems to be rendered as an unordered list <ul>.  I have tried changing the "RepeatDirection" to "Horizontal" and the "RepeatLayout" to "Table".  None of this makes any difference.

    What am I missing about using RadioButtonLists within a Control Designer?

    Thanks,

    Gabe
    ==========
  8. Slavo
    Slavo avatar
    295 posts
    Registered:
    24 Sep 2012
    09 Oct 2007
    Link to this post
    Hi Gabe,

    The reason your RadioButtonLists are rendered as <ul> is that we have provided an adapter for them. We use a custom class to render radio buttons in an unordered list and this is how they are in all places of Sitefinity's administration. You would have to modify your css to style them as they are now, or you would have to remove the adapter. In the second case, however, they would look ugly in the places where we have used them in our controls. Still, if you want to remove the adapter, edit the BrowserFile.browser, located in the App_Browsers folder of your project, and remove the line highlighted below:

    <controlAdapters> 
          <adapter controlType="System.Web.UI.HtmlControls.HtmlForm" adapterType="Telerik.Cms.Web.FormAdapter, Telerik.Cms" /> 
          <adapter controlType="System.Web.UI.WebControls.RadioButtonList" adapterType="Telerik.Cms.Web.UI.Adapters.RadioButtonListAdapter" /> 
        </controlAdapters>

    Of course, I recommend styling the RadioButtonLists with custom CSS.
    Please, let us know if this helps.

    Greetings,
    Slavo
    the Telerik team

    Instantly find answers to your questions at the new Telerik Support Center
  9. Gabe Sumner
    Gabe Sumner avatar
    440 posts
    Registered:
    09 Sep 2007
    09 Oct 2007
    Link to this post
    Got it.

    I tried adding a stylesheet (css) file to:

    ~/Sitefinity/Admin/Themes/Default

    If I add a "css" file to this folder it doesn't seem to get loaded or included on the rendered Control Designer page.

    I know I could directly alter the "CtrlProp.css", however I would prefer to avoid changing Sitefinity core files.  I would like to keep a clean division between "my stuff" and "Sitefinity stuff".

    Perhaps you could comment generally on this?  What is the prefered method of applying additional stylesheets to Control Designers?

    Thanks,

    Gabe
    ===============
  10. Gabe Sumner
    Gabe Sumner avatar
    440 posts
    Registered:
    09 Sep 2007
    09 Oct 2007
    Link to this post
    Here is the method I came up with for referencing my own custom stylesheets:

    protected override void OnPreRender(EventArgs e)  
    {  
        base.OnPreRender(e);  
     
        HtmlLink css = new HtmlLink();  
        css.Href = "/UserControls/ControlDesigner.css";  
        css.Attributes.Add("rel", "stylesheet");  
        css.Attributes.Add("type", "text/css");  
     
        this.Page.Header.Controls.Add(css);  

    I put this code in my "ControlDesigner" cs file.

    I would still love to know if this is the preferred method.  Thanks.

    Gabe
    ================
  11. Slavo
    Slavo avatar
    295 posts
    Registered:
    24 Sep 2012
    10 Oct 2007
    Link to this post
    Hi Gabe,

    In general, the preferred method always depends on the preferences of the designer or programmer. We do not limit anyone to do things in a certain way and always try to provide flexibility and extensibility in all parts of our product. How you apply additional styling to your control designer depends on you. Since you said you want to keep what we've done and what you've done separate, then I guess it's better to use an additional stylesheet and include it with the code you've shown. You can of course backup our original CSS files and modify them to suit your needs. Even if you make a mistake, they are always available in the /ProjectManager/EmptyProject folder of your Sitefinity installation. The code you've provided looks good and I suggest you use it.

    Greetings,
    Slavo
    the Telerik team

    Instantly find answers to your questions at the new Telerik Support Center
Register for webinar
11 posts, 0 answered