More in this section

Forums / Developing with Sitefinity / Creating Custom Properties for User Controls

Creating Custom Properties for User Controls

15 posts, 0 answered
  1. Mike
    Mike avatar
    9 posts
    Registered:
    15 Aug 2007
    15 Aug 2007
    Link to this post
    I am trying to create a basic user control that contains a hyperlink and a button.  I have created a property for the url and the display text for the url.

    What I want to do is set up the URL field so that it uses properties window will allow you to pick from the list of files that already exist.  It seems that the documentation suggests setting the WebEditor attribute, but I cannot figure out what to set it to.  I have set it to just about everything I could find in the documentation, and also tried creating the property typed as Uri .

    Source code from the codebehind:

        protected void Page_Load(object sender, EventArgs e)
        {
            if (_title == null) _title = "";
            Link1.InnerHtml = "<strong>" + _title + "</strong>";
            if (_url != null)
            {
                Link1.HRef = _url;
                Link2.HRef = _url;
            }
        }
       
        private string _url;
        [WebEditor("CmsUrlWebEditor")]
        public string Url
        {
            get { return _url;}
            set { _url = value;}
        }

        private string _title;

        public string LinkText
        {
            get { return _title; }
            set { _title = value; }
        }

  2. UI Crew
    UI Crew avatar
    99 posts
    Registered:
    24 Sep 2012
    16 Aug 2007
    Link to this post
    Hi,

    I think the Image Gallery in the blogs uses the exact think you want to pick folders.

    Have a look at how it's done: http://blogs.sitefinity.com/Ivan/Post/07-07-23/image_gallery_for_sitefinity_a_better_one_.aspx

    Hope that helps.

    Seth
  3. Vlad
    Vlad avatar
    498 posts
    Registered:
    19 Jun 2017
    16 Aug 2007
    Link to this post
    Hi Mike,

    You should set the full type of the class for the WebEditor attribute.
    For example:

    [WebEditor("Telerik.Cms.Web.UI.UrlEditorWrapper, Telerik.Cms")]  
    public string Url  
    {  
        get { return _url;}  
        set { _url = value;}  

    or:

    [WebEditor("Telerik.Cms.Web.UI.CmsUrlWebEditor, Telerik.Cms")]        
    public string Url        
    {        
        get { return _url;}        
        set { _url = value;}        
    }       
        
     


    Regards,
    Vlad
    the Telerik team

    Instantly find answers to your questions at the new Telerik Support Center
  4. Mike
    Mike avatar
    9 posts
    Registered:
    15 Aug 2007
    16 Aug 2007
    Link to this post
    Thank you Vlad, that works wonderful.

    I have a few more questions:
    1.  What do I set the attribute to, in order to get a Content Editor, like you get for generic content?  I tried            [WebEditor("Telerik.Cms.Engine.WebControls.HtmlContentEditor, Telerik.Cms")]
        public string Content
        {
            get { return (_content == null)? String.Empty:_content; }
            set { _content = value; }
        }
     which resulted in a NullReferenceException.

    2.  If I wanted to create a control that allows content sharing similar to the functionality of the Generic Content Control, I would have to create a module, or would this be possible by setting an attribute?
  5. Vlad
    Vlad avatar
    498 posts
    Registered:
    19 Jun 2017
    17 Aug 2007
    Link to this post
    Hello Mike,

    You are on the right way, you just made a mistake in declaring the type of the WebEditor, because Telerik.Cms.Engine.WebControls.HtmlContentEditor is in Telerik.Cms.Engine, not in Telerik.Cms assembly.

    To create such a control, you should create a WebControl which implements IContentContainer interface. The IContentContainer.Contents property of that control should have an attribute which implements IWebUITypeEditor interface, e.g.

    [Browsable(false)]  
    [WebEditor("Telerik.Cms.Engine.WebControls.HtmlContentEditor, Telerik.Cms.Engine")]  
    [TypeConverter(typeof(StringConverter))]  
    public object Content 


    Therefore, you should also create a WebEditor control or use an existing one e.g. Telerik.Cms.Engine.WebControls.HtmlContentEditor. This control will be displayed in the Content tab when editing the IContentContainer control.

    In case your WebEditor is Telerik.Cms.Engine.WebControls.HtmlContentEditor, you will be able to use all its functionality such as content sharing and branching.

    By the way, we are now working on control designers feature which is to be part of the 3.1 version release. This feature will provide mechanism for creating control designers for editing the control properties. The designer control will be an alternative way for editing the control. It will appear on the left side of the Properties tab (like in GenericContent). The idea is to have a user-friendly interface for editing the most popular properties of the control.

    Please let us know if you have additional questions.


    Regards,
    Vlad
    the Telerik team

    Instantly find answers to your questions at the new Telerik Support Center
  6. Mike
    Mike avatar
    9 posts
    Registered:
    15 Aug 2007
    20 Aug 2007
    Link to this post
    Thanks again for your support.

    I am creating a control to edit and display a list of links.  So I have created a Link class which contains properties for Text, Url, and OpenNewWindow (to set the target to a new window).

    1public class Link 
    2
    3    public Link() 
    4    { 
    5        // 
    6        // TODO: Add constructor logic here 
    7        // 
    8    } 
    9 
    10    private string _displayText = ""
    11 
    12    public string Text 
    13    { 
    14        get { return _displayText; } 
    15        set { _displayText = value; } 
    16    } 
    17 
    18    private string _url = ""
    19 
    20    public string Url 
    21    { 
    22        get { return _url; } 
    23        set { _url = value; } 
    24    } 
    25 
    26    private bool _openNewWindow = false
    27 
    28    public bool OpenNewWindow 
    29    { 
    30        get { return _openNewWindow; } 
    31        set { _openNewWindow = value; } 
    32    } 
    33
    34 

    I have created a UserControl called RelatedPages which is going to display the list of Pages as follows (there is no code except the property right now, I will write the display code once I get the editor to work.):

    public partial class UserControls_RelatedPages : System.Web.UI.UserControl 
        protected void Page_Load(object sender, EventArgs e) 
        { 
     
        } 
     
        private List<Link> _link; 
     
        [WebEditor("LinkListEditor")] 
        public List<Link> ActionLink 
        { 
            get { return _link; } 
            set { _link = value; } 
        } 


    I also extended the WebUITypeEditor class as follows:
    1public class LinkListEditor : WebUITypeEditor<List<Link>> 
    2    { 
    3    public LinkListEditor() 
    4    { 
    5        myList = new List<Link>(); 
    6    } 
    7
    8    #region :::Properties::::::::::::::::: 
    9 
    10    private List<Link> myList; 
    11    CheckBox chbNewWindow; 
    12    TextBox txtText, txtUrl; 
    13 
    14    /// <summary> 
    15    /// Overriden property of WebUITypeEditor. When user clicks "I'm done" this value is being sent 
    16    /// back to the property that opened this editor. 
    17    /// </summary> 
    18    public override List<Link> Value 
    19    { 
    20        get 
    21        { 
    22            Link aLink = new Link(); 
    23            aLink.OpenNewWindow = chbNewWindow.Checked; 
    24            aLink.Text = txtText.Text; 
    25            aLink.Url = txtText.Text; 
    26            myList.Add(aLink); 
    27            return myList; 
    28        } 
    29        set 
    30        { 
    31            myList = value; 
    32        } 
    33    } 
    34
    35    #endregion 
    36
    37    #region Methods 
    38 
    39    /// <summary> 
    40    /// Called by ASP.NET. Creates child controls for this control. 
    41    /// </summary> 
    42    protected override void CreateChildControls() 
    43    { 
    44        this.Controls.Clear(); 
    45 
    46        // NOTE : this control can be much more complex in a real scenario. You could implement for example 
    47        // gridview and bind it to a database and then let user to select a value.  
    48 
    49        // Text Control 
    50        Label lblMessage = new Label(); 
    51        lblMessage.Text = "Display Text: "
    52        this.Controls.Add(lblMessage); 
    53 
    54        txtText = new TextBox(); 
    55        txtText.Text = (myList.Count > 0)? myList[0].Text : ""
    56        this.Controls.Add(txtText); 
    57 
    58        // Url Control 
    59        lblMessage = new Label(); 
    60        lblMessage.Text = "Url: "
    61        this.Controls.Add(lblMessage); 
    62 
    63        txtUrl = new TextBox(); 
    64        txtUrl.Text = (myList.Count > 0)? myList[0].Url : ""
    65        this.Controls.Add(txtUrl); 
    66 
    67        // OpenNewWindow Control 
    68        lblMessage = new Label(); 
    69        lblMessage.Text = "Open Link in New Window: "
    70        this.Controls.Add(lblMessage); 
    71 
    72        chbNewWindow = new CheckBox(); 
    73        chbNewWindow.Checked = (myList.Count > 0)? myList[0].OpenNewWindow : false
    74        this.Controls.Add(txtText); 
    75    } 
    76    #endregion 
    77 
    78

    For testing purposes, I am only reading, and editing the first value of the List, but once this works, I will allow multiple List entries.

    I am thinking that I may have to implement ISerializable, is this correct?
  7. Vlad
    Vlad avatar
    498 posts
    Registered:
    19 Jun 2017
    21 Aug 2007
    Link to this post
    Hi Mike,

    The problem is that the type List <Link> cannot be converted from string. Only types, which can be converted from/to string can be edited with the Property Viewer.

    There are two approaches:
     
      1) Choose another type for the ActionLink property;
     
      2) Create a custom TypeConverter for the ActionLink property:
        public class ExtCollectionConverter : System.ComponentModel.CollectionConverter  
        {  
            public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)  
            {  
                if (sourceType == typeof(string))  
                    return true;  
                return base.CanConvertFrom(context, sourceType);  
            }  
     
            public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)  
            {  
                if (sourceType == typeof(string))  
                    return true;  
                return base.CanConvertTo(context, destinationType);  
            }  
     
            public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)  
            {  
                if (sourceType == typeof(string))  
                {   
                    // Add your code here  
                }  
                return base.ConvertFrom(context, culture, value);  
            }  
     
            public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)  
            {  
                if (sourceType == typeof(string))  
                {   
                    // Add your code here     
                }  
                return base.ConvertTo(context, culture, value, destinationType);  
            }  
        }  
     

        [TypeConverter(typeof(ExtCollectionConverter)), WebEditor("LinkListEditor")]  
        public List<Link> ActionLink  
        {  
            get { return _link; }  
            set { _link = value; }  
        }    
     


    Hope this is helpful.


    Regards,
    Vlad
    the Telerik team

    Instantly find answers to your questions at the new Telerik Support Center
  8. Mike
    Mike avatar
    9 posts
    Registered:
    15 Aug 2007
    21 Aug 2007
    Link to this post
    I implemented your code, a wrote the code to store the List's data in a string and vise versa.  However, I still get the same error:

    Could not find any resources appropriate for the specified culture or the neutral culture.  Make sure "Telerik.Resources.Messages.resources" was correctly embedded or linked into assembly "Telerik.Framework" at compile time, or that all the satellite assemblies required are loadable and fully signed.

    Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

    Exception Details: System.Resources.MissingManifestResourceException: Could not find any resources appropriate for the specified culture or the neutral culture.  Make sure "Telerik.Resources.Messages.resources" was correctly embedded or linked into assembly "Telerik.Framework" at compile time, or that all the satellite assemblies required are loadable and fully signed.

    Source Error:

    An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.

    Stack Trace:

    [MissingManifestResourceException: Could not find any resources appropriate for the specified culture or the neutral culture.  Make sure "Telerik.Resources.Messages.resources" was correctly embedded or linked into assembly "Telerik.Framework" at compile time, or that all the satellite assemblies required are loadable and fully signed.]
    System.Resources.ResourceManager.InternalGetResourceSet(CultureInfo culture, Boolean createIfNotExists, Boolean tryParents) +655
    System.Resources.ResourceManager.InternalGetResourceSet(CultureInfo culture, Boolean createIfNotExists, Boolean tryParents) +681
    System.Resources.ResourceManager.InternalGetResourceSet(CultureInfo culture, Boolean createIfNotExists, Boolean tryParents) +681
    System.Resources.ResourceManager.GetString(String name, CultureInfo culture) +77
    Telerik.Resources.Messages.get_InvalidResXNoType() +45
    Telerik.Utilities.TypeResolutionService.GetType(String name, Boolean throwOnError, Boolean ignoreCase) +951
    Telerik.Utilities.TypeResolutionService.ResolveType(String name, Boolean throwOnError, Boolean ignoreCase) +95
    Telerik.Cms.Web.UI.PropertyEditorDialog.GetEditor() +244
    Telerik.Cms.Web.UI.PropertyEditorDialog.CreateChildControls() +175
    System.Web.UI.Control.EnsureChildControls() +87
    Telerik.Cms.Web.UI.PropertyEditorDialog.Show(String propertyName, String typeName, Object data, Object typeContainer) +84
    Telerik.Cms.Web.UI.PropertyView.picker_Command(Object sender, CommandEventArgs e) +352
    System.Web.UI.WebControls.LinkButton.OnCommand(CommandEventArgs e) +105
    System.Web.UI.WebControls.LinkButton.RaisePostBackEvent(String eventArgument) +163
    System.Web.UI.WebControls.LinkButton.System.Web.UI.IPostBackEventHandler.RaisePostBackEvent(String eventArgument) +7
    System.Web.UI.Page.RaisePostBackEvent(IPostBackEventHandler sourceControl, String eventArgument) +11
    System.Web.UI.Page.RaisePostBackEvent(NameValueCollection postData) +174
    System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +5102


    If there is any information I can give you to help, let me know.
  9. Vlad
    Vlad avatar
    498 posts
    Registered:
    19 Jun 2017
    23 Aug 2007
    Link to this post
    Hello Mike,

    The error you have posted is related to an incorrect namespace of the resource messages in Telerik.Framework assembly. It is already fixed for 3.1

    But the actual error most probably is:
    "Could not find a type for a name.  The type name was 'LinkListEditor'".

    To fix the problem you should specify the full type name (with an Assembly name) for the WebEditor attribute, e.g:

    [WebEditor("Telerik.Cms.Engine.WebControls.HtmlContentEditor, Telerik.Cms.Engine")]

    We found that the types declared in the App_Code of the Web Site are not supported as property web editors in the current release. We will consider how to improve our system regarding this issue. 
    At the time being you should create another code library project to implement your custom LinkListEditor WebEditor.

    We hope this will help, please let us know how it goes.

    Best wishes,
    Vlad
    the Telerik team

    Instantly find answers to your questions at the new Telerik Support Center
  10. Mike
    Mike avatar
    9 posts
    Registered:
    15 Aug 2007
    17 Sep 2007
    Link to this post
    Hello again,
    I would like to create a dropdownlist control that would contain the names of the child pages of the current page.  Of course, since the editor is implemented in an iframe, Sitemap.currentnode, Request.Url and Request.UrlReferrer return admin pages so I cannot determine the page that is being edited.  Is there some other way to get the current page that I have overlooked that would enable me to list child pages?

    Also, I would like to be able to show pages in the dropdownlist that may not yet be approved to production and therefor might not be included in the sitemap object.  Is there a different provider I can use that gives me the equivalent of the SiteMap in Sitefinity which includes all pages wether they are approved or not?

    Let me know if you need clarification or code samples for any of this.
  11. Pepi
    Pepi avatar
    981 posts
    Registered:
    31 Jan 2017
    18 Sep 2007
    Link to this post
    Hello Mike,

    In the attachment you can find an example how to achieve the required functionality.

    Hope this helps.

    All the best,
    Pepi
    the Telerik team

    Instantly find answers to your questions at the new Telerik Support Center
  12. Mike
    Mike avatar
    9 posts
    Registered:
    15 Aug 2007
    18 Sep 2007
    Link to this post
    I may not have explained myself very well, but what I actually need is the same functionality, but in a Control on the WebUITypeEditor Page.

    Basically I want the content team to be able to choose a child page (which are going to be pages describing a list of products called a 'group page'), and then pull the metadata from that list of products.

    This time I will attach my code for a clearer understanding of what I am working with:
    1    class ChildPagePicker : WebUITypeEditor<string
    2    { 
    3        #region :::Constructors:::::::::::::::: 
    4 
    5        public ChildPagePicker() 
    6        { 
    7            _groupPage = String.Empty; 
    8        } 
    9
    10        #endregion 
    11
    12        #region :::Properties::::::::::::::::: 
    13 
    14        private string _groupPage; 
    15        DropDownList _groupPages; 
    16 
    17        /// <summary> 
    18        /// Overriden property of WebUITypeEditor. When user clicks "I'm done" this value is being sent 
    19        /// back to the property that opened this editor. 
    20        /// </summary> 
    21        public override string Value 
    22        { 
    23            get 
    24            { 
    25                return _groupPages.SelectedValue; 
    26            } 
    27            set 
    28            { 
    29                _groupPage = value; 
    30            } 
    31        } 
    32
    33        #endregion 
    34
    35        #region :::Methods::::::::::::::::::::: 
    36 
    37        /// <summary> 
    38        /// Called by ASP.NET. Creates child controls for this control. 
    39        /// </summary> 
    40        protected override void CreateChildControls() 
    41        { 
    42            this.Controls.Clear(); 
    43 
    44            // NOTE : this control can be much more complex in a real scenario. You could implement for example 
    45            // gridview and bind it to a database and then let user to select a value.  
    46 
    47            // Text Control 
    48            Label lblMessage = new Label(); 
    49            lblMessage.Text = "Please choose a Group Page: "
    50            this.Controls.Add(lblMessage); 
    51 
    52            _groupPages = new DropDownList(); 
    53 
    54            foreach (SiteMapNode Node in SiteMap.RootNode.GetAllNodes()) 
    55            { 
    56                if (Node.HasChildNodes) _groupPages.Items.Add(new ListItem(Node.Title, Node.Url)); 
    57            } 
    58            try 
    59            { 
    60                _groupPages.SelectedValue = _groupPage; 
    61            } 
    62            catch { } 
    63            this.Controls.Add(_groupPages); 
    64 
    65            } 
    66        #endregion 
    67 
    68 
    69        } 
    70    } 

    For the time being I am grabbing the list of child pages with
                 foreach (SiteMapNode Node in SiteMap.RootNode.GetAllNodes())
    but I would like to grab only the pages that are child pages of the current page being edited instead.

    I also tried modifying this to use CmsUrlContext, but CmsUrlContext returns null when in the property editor, as does Sitemap.currentnode and Request.Url and Request.UrlReferrer both return the url of the control editor.

    Thanks, Mike
  13. Vassil Daskalov
    Vassil Daskalov avatar
    261 posts
    Registered:
    18 May 2013
    19 Sep 2007
    Link to this post
    Hello Mike,

    Unfortuantely, you cannot retrieve the page URL from server side inside control within the RadWindow as you only have reference to the page inside the RadWindow. One possible solution would be to retrieve the page URL via JavaScript.

    You could add hidden input in the CtrlProps.aspx page and fullfil its value with the window.top.location. In the server side of your selector you could retrieve the input value this way:

    (this.Page.FindControl("myInput") as HtmlInputHidden).Value

    Hope this helps.

    Regards,
    Vassil Daskalov
    the Telerik team

    Instantly find answers to your questions at the new Telerik Support Center
  14. Mike
    Mike avatar
    9 posts
    Registered:
    15 Aug 2007
    26 Sep 2007
    Link to this post
    Thank you for your reply.  I suppose that obtaining the page url through javascript would work, but would I be able to do it programmaticaly in the codebehind?  I'd prefer to not modify the sitefinity code, as this could lead to a bunch of upgrade incompatibities down the road when there are new versions of sitefinity like 3.1 for instance.

    Is there a way to either:
    Detemermine the Guid of the current page? or
    Determine the Guid of the control being edited, which can be mapped to the Guid of the Page?



  15. Vlad
    Vlad avatar
    498 posts
    Registered:
    19 Jun 2017
    27 Sep 2007
    Link to this post
    Hello Mike,

    You will be able to determine the Page of the editable control in version 3.1. The page ID will be sent to the Control Properties dialog in the QueryString.

    Sincerely yours,
    Vlad
    the Telerik team

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