More in this section

Forums / Developing with Sitefinity / Using SiteMapPanel with WebEditorAttribute

Using SiteMapPanel with WebEditorAttribute

15 posts, 0 answered
  1. Jason Grovert
    Jason Grovert avatar
    28 posts
    Registered:
    25 Oct 2005
    24 May 2007
    Link to this post
    We need to use the SiteMapPanel or one that has the same functionality when Editing properties on some of our Custom Web User Controls.  When we try and use the SiteMapPanel control we get an error when trying to edit the control.
  2. Bogdana Ivanova
    Bogdana Ivanova avatar
    66 posts
    Registered:
    24 Sep 2012
    25 May 2007
    Link to this post
    Hi Jason,

    We would be grateful if you send as much information as possible about your goals and about the error message, in order to be able to investigate the problem. This would help us a lot.
    Meanwhile, I am sending you a link to a blog post about working with complex properties in custom public controls. I suppose that it might help you to fix the problem:

    http://sitefinity.wordpress.com/2007/05/25/working-with-complex-properties-in-custom-public-controls-webtypeeditor/

    Thanks in advance for your cooperation!

    Best wishes,

    Bogdana Ivanova
    the Telerik team

    Instantly find answers to your questions at the new Telerik Support Center
  3. Jason Grovert
    Jason Grovert avatar
    28 posts
    Registered:
    25 Oct 2005
    25 May 2007
    Link to this post
    Our goal is to provide the user the ability to select an existing Page from some sort of SiteMap user control that will be linked to using an anchor tag within a Custom Web UserControl that we have created.  We have several different types of controls that provide similar functionality using a HyperLinks, LInkButtons, and/or Flash objects.

    The SiteMap functionality we seek is very similar to the SiteMap control that is used on Pages.aspx on the Admin side of the site.  We were hoping to just reuse that control as our WebEditor for our Web UserControl property that will store the destination (href) for the anchor tag control.

    The sample you've provided may work for us in the event we cannot get the SiteMapPanel to work.  See below for the error message we receieve when trying to use that control as our WebEditor.

    =============================================================

      Server Error in '/' Application.
    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() +24
     Telerik.Utilities.TypeResolutionService.GetType(String name, Boolean throwOnError, Boolean ignoreCase) +717
     Telerik.Utilities.TypeResolutionService.ResolveType(String name, Boolean throwOnError, Boolean ignoreCase) +68
     Telerik.Cms.Web.UI.PropertyEditorDialog.GetEditor() +150
     Telerik.Cms.Web.UI.PropertyEditorDialog.CreateChildControls() +155
     System.Web.UI.Control.EnsureChildControls() +87
     Telerik.Cms.Web.UI.PropertyView.picker_Command(Object sender, CommandEventArgs e) +284
     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
    


    Version Information: Microsoft .NET Framework Version:2.0.50727.42; ASP.NET Version:2.0.50727.210
  4. iosmak
    iosmak avatar
    18 posts
    Registered:
    12 Oct 2006
    25 May 2007
    Link to this post
    Hi Jason,

    there is a special kind of WebEditor already provided by Sitefinity that you can use to allow your users to choose a page or file. It's called : 

    Telerik.Cms.Web.UI.UrlEditorWrapper

    I've created a simple user control that let's user select a page for the HyperLink control. You can download it here : 
    http://iosmak.googlepages.com/LinkControl.zip

    Thanks,
    Ivan

  5. Jason Grovert
    Jason Grovert avatar
    28 posts
    Registered:
    25 Oct 2005
    25 May 2007
    Link to this post
    Thanks for the quick reply, but that control doesn't do exactly what we need.  I should have clarified the fact that we are using Url ReWriting and perfer to store the GUID (Id) for the selected page so in the event someone should rename the page the link will not break.  We also build our sitemap programatically so storing the actual page name won't work for us either.
  6. iosmak
    iosmak avatar
    18 posts
    Registered:
    12 Oct 2006
    25 May 2007
    Link to this post
    Hi Jason,

    ok I think I finally understood you. Sorry it took so long :) .

    The way I see it, you have to options :

    1. Create your own WebEditor control which would return page url and page id (guid value) as dependent property (you'll need to implement IControlPropertyEditor interface on that class). I'll try to write a blog post in next few days on sitefinity.wordpress.com about this.

    2. Second option is easier to implement, but you'll need to cache the page id's and I'm not sure if that would work for you. Anyhow, here is the modified user control that I've attached in my previous reply which should satisfy your needs.

    using System; 
    using System.Data; 
    using System.Configuration; 
    using System.Collections; 
    using System.Web; 
    using System.Web.Security; 
    using System.Web.UI; 
    using System.Web.UI.WebControls; 
    using System.Web.UI.WebControls.WebParts; 
    using System.Web.UI.HtmlControls; 
    using System.ComponentModel; 
    using Telerik.Cms.Web.UI; 
    using Telerik.Cms; 
     
     
    public partial class MyControls_LinkControl : System.Web.UI.UserControl 
         
        [WebEditor("Telerik.Cms.Web.UI.UrlEditorWrapper, Telerik.Cms")] 
        public string LinkUrl 
        { 
            get 
            { 
                // if pageId is set, check the actual url based on the pageId 
                if (pageId != Guid.Empty) 
                { 
                    CmsManager manager = new CmsManager(); 
                    ICmsPage page = manager.GetPage(pageId) as ICmsPage; 
                    this.linkUrl = page.DefaultUrl.Url; 
                } 
                return this.linkUrl; 
            } 
            set 
            { 
                this.linkUrl = value; 
                // when user sets linkUrl, find the id of that page and set pageId 
                Telerik.Cms.Web.CmsSiteMapNode node = (Telerik.Cms.Web.CmsSiteMapNode)SiteMap.Provider.FindSiteMapNode(this.linkUrl); 
                if (node != null
                    pageId = node.CmsPage.ID; 
            } 
        } 
         
        protected void Page_Load(object sender, EventArgs e) 
        { 
                Link.NavigateUrl = LinkUrl; 
        } 
     
        string linkUrl; 
        static Guid pageId; 
     

    I hope this helps.

    Thanks,
    Ivan
  7. Jason Grovert
    Jason Grovert avatar
    28 posts
    Registered:
    25 Oct 2005
    29 May 2007
    Link to this post

    Hi Ivan,

    We're almost there but we're having some problems with displaying the Guid of the Page selected using the UrlEditor control.  For some reason the Url is being displayed in the PrimaryLink Property (see below) instead of the Guid.  Once we save and return the Guid displays as expected.  We're also wanting to set the default Text value of the link (see LinkDefaultText).  We then give them the option of overriding that Text value (see LinkOverrideText).  The LinkDefaultText value doesn't get updated initially either.  Any ideas?

        private string _linkDefaultText;
        [ReadOnly( true )]
        public string LinkDefaultText
        {
            get
            {
                return _linkDefaultText;
            }
            set
            {
                string pageLanguage = this.Context.Items["PageLanguage"] == null ? "en-US" : this.Context.Items["PageLanguage"].ToString();
                this._linkDefaultText = RylandSiteFinity.GetDisplayPageName( value, pageLanguage );
            }
        }
        private string _linkOverrideText;
        public string LinkOverrideText
        {
            get
            {
                return _linkOverrideText;
            }
            set
            {
                _linkOverrideText = value;
            }
        }
        private string _primaryLink;
        [WebEditor( "Telerik.Cms.Web.UI.UrlEditorWrapper, Telerik.Cms" )]
        //[WebEditor( "RylandUserControls.RylandSiteMap, RylandUserControls" )]
        public string PrimaryLink
        {
            get
            {
                if( !Munipulate.IsGuid( this._primaryLink ) )
                {
                    string pageLanguage = this.Context.Items["PageLanguage"] == null ? "en-US" : this.Context.Items["PageLanguage"].ToString();
                    return RylandSiteFinity.GetPageGuidByName( this._primaryLink, pageLanguage );
                }
                else
                {
                    return _primaryLink;
                }
            }
            set
            {
                if( !Munipulate.IsGuid( value ) && !string.IsNullOrEmpty( value ) )
                {
                    string pageLanguage = this.Context.Items["PageLanguage"] == null ? "en-US" : this.Context.Items["PageLanguage"].ToString();
                    this.LinkDefaultText = RylandSiteFinity.GetDisplayPageName( value, pageLanguage );
                    this.PrimaryLink = RylandSiteFinity.GetPageGuidByName( value, pageLanguage );
                }
                else
                {
                    if( Munipulate.IsGuid( value ) )
                    {
                        this.LinkDefaultText = RylandSiteFinity.GetPageUrlByGuid( value );
                        this._primaryLink = value;
                    }
                }
            }
        }

    We tried creating our own WebEditor based on your blog but get the same Resource Exception we reported previously.  I can send you the code if that would help.

    This functionality is used in quite a fiew of our User Controls so getting this working the way we need it to is very important to us.  Your help is greatly appreciated.

  8. iosmak
    iosmak avatar
    18 posts
    Registered:
    12 Oct 2006
    30 May 2007
    Link to this post
    Hi Jason,

    let me first explain why is your code not working before you hit "I'm done" and open the property editor again. The thing is that property editor (that pop-up that opens when you click 'edit') is another control, based on the properties of your control. So you can't set for example DefaultText in the set part of the PrimaryLink property.

    To achieve your goal you need to create your own WebEditor with dependent properties. Since you are experiencing problems with that, I'd be more than glad to help you with that.

    Please, attach your user control and the WebEditor that appears not to be working and I'll modify it and attach it back.

    Thanks,
    Ivan
  9. Jason Grovert
    Jason Grovert avatar
    28 posts
    Registered:
    25 Oct 2005
    30 May 2007
    Link to this post
    Since we cannot attach files to a Forum posting we've placed the files on our file server for you to download.

    http://images.ryland.com/it/rylandusercontrols.zip

    Thanks again for your help.
  10. iosmak
    iosmak avatar
    18 posts
    Registered:
    12 Oct 2006
    30 May 2007
    Link to this post
    Hi Jason,

    I've modified the files you've sent me and uploaded the zip file on this address :
    http://iosmak.googlepages.com/ryland_modified.zip

    Here is briefly what I've done :

    1. Used your web editor and modified it to inherit CmsUrlWebEditor (which will show the sitemap and do all that work for you regarding the page selection) and in addition to that I've made it implement IControlPropertyEditor interface.

    2. Added DependentProperties property which lets you pass back as many values for properties apart from the one you are actually editing (in your case PrimaryLink). This is how that looks like :

    public IDictionary<stringobject> DependentProperties 
            { 
                get 
                { 
                    if (this.dependentProps == null
                    { 
                        this.dependentProps = new Dictionary<stringobject>(); 
                        this.dependentProps.Add("PageId"this.pageId); 
                        this.dependentProps.Add("LinkDefaultText"this.linkDefaultText); 
                    } 
                    else 
                    { 
                        if (base.ChildControlsCreated) 
                        { 
                            SetDependentProperties(base.Value); 
                        } 
                    } 
                         
                    return this.dependentProps; 
                } 
            } 

    So, just to make a point I've added PageId and LinkDefaultText properties. It is important that keys of DependentProperties dictionary have coresponding properties in the web control (that's how the property editor knows which other property to modify).

    There is another method called SetDependentProperties, which is roughly same to one of the methods I've wrote in one of my previous posts. This method is actually setting the values of dependent properties :

    private void SetDependentProperties(string linkUrl) 
            { 
                string selectedUrl = linkUrl; 
                CmsManager manager = new CmsManager(); 
                Telerik.Cms.Web.CmsSiteMapNode node = (Telerik.Cms.Web.CmsSiteMapNode)SiteMap.Provider.FindSiteMapNode(base.Value); 
                if (node != null
                { 
                    this.pageId = node.CmsPage.ID; 
                    this.linkDefaultText = node.CmsPage.MenuName; 
                } 
     
                this.dependentProps["PageId"] = this.pageId; 
                this.dependentProps["LinkDefaultText"] = this.linkDefaultText; 
            } 

    One important thing to note is that dependent properties must be browsable (default) and can't be read-only.

    I hope this helps.

    Thanks,
    Ivan

    - To other readers how are interested in working with dependent properties, but are out of the loop on our dicsussion, I'll be blogging on this subject in next several days on sitefinity.wordpress.com


  11. Jason Grovert
    Jason Grovert avatar
    28 posts
    Registered:
    25 Oct 2005
    31 May 2007
    Link to this post
    Hi Ivan!,

    Your solution works great, but I was wondering if there's a way to make the Dependency fields dynamic?  Maybe pass them in as parameters to the WebEditorAttribute?  We need to use this type of functionality on serveral different Web User Controls who's field names are all unique.  Therefore, we'd have to create a class for each User Control and were hoping to avoid doing that.  Thanks!
  12. Bogdana Ivanova
    Bogdana Ivanova avatar
    66 posts
    Registered:
    24 Sep 2012
    04 Jun 2007
    Link to this post
    Hi Jason,

    We are happy to hear that we helped. Regarding the dynamic dependency fields, we have a solution but we think it is not the perfect one. We need some more time to find if something better could be done. We will write you as soon as we finish with our research. 
     
    Regards,
    Bogdana Ivanova
    the Telerik team

    Instantly find answers to your questions at the new Telerik Support Center
  13. iosmak
    iosmak avatar
    18 posts
    Registered:
    12 Oct 2006
    06 Jun 2007
    Link to this post
    Hi Jason,

    first I'd like to apologize because you had to wait this long for an answer. So the way I see it you have two options to accomplish your task :

    1. Create one base class editor and then create a class for every type of editor that you need. In the derived classes you would override only the DependentProperties property with the one you need.

    2. You can use one editor class and create a new DependentProperties dictionary based on which control opened the editor. To accomplish that you would need to use code similar to the following :

    using System; 
    using System.Collections.Generic; 
    using System.Text; 
    using System.Web; 
    using Telerik.Cms.Web.UI; 
    using Telerik.WebControls; 
    using Telerik.Cms.Web; 
    using System.Web.UI.WebControls; 
    using System.ComponentModel; 
    using Telerik.Cms; 
     
    namespace RylandUserControls 
        public class RylandSiteMap : CmsUrlWebEditor, IControlPropertyEditor 
        { 
            #region Properties 
     
            public IDictionary<stringobject> DependentProperties 
            { 
                get 
                { 
                    if (this.dependentProps == null
                    { 
                        switch(base.TypeContainer.ToString()) 
                        { 
                            // in case user control "UserControls/Right_Nav_Generic.ascx" 
                            // called this editor 
                            case "ASP.usercontrols_right_nav_generic_ascx"
                                this.dependentProps = new Dictionary<stringobject>(); 
                                this.dependentProps.Add("PageId"this.pageId); 
                                this.dependentProps.Add("LinkDefaultText"this.linkDefaultText); 
                                break
                            // in case user control "UserControls/Generic_Link.ascx" 
                            // called this editor 
                            case "ASP.usercontrols_generic_link_ascx"
                                this.dependentProps = new Dictionary<stringobject>(); 
                                this.dependentProps.Add("SomeOtherProperty", String.Empty); 
                                break
                        } 
                    } 
                    else 
                    { 
                        if (base.ChildControlsCreated) 
                        { 
                            SetDependentProperties(base.Value); 
                        } 
                    } 
                         
                    return this.dependentProps; 
                } 
            } 
            #endregion 
     
            protected override void OnInit(EventArgs e) 
            { 
                base.OnInit(e); 
                if (this.Page != null
                    this.Page.RegisterRequiresControlState(this); 
            } 
     
            protected override void LoadControlState(object savedState) 
            { 
                if (savedState != null
                { 
                    object[] state = (object[])savedState; 
                    this.pageId = (Guid)state[0]; 
                    this.linkDefaultText = (string)state[1]; 
                } 
            } 
     
            protected override object SaveControlState() 
            { 
                return new object[] {   
                    this.pageId, 
                    this.linkDefaultText 
                }; 
            } 
     
            private void SetDependentProperties(string linkUrl) 
            { 
                string selectedUrl = linkUrl; 
                CmsManager manager = new CmsManager(); 
                Telerik.Cms.Web.CmsSiteMapNode node = (Telerik.Cms.Web.CmsSiteMapNode)SiteMap.Provider.FindSiteMapNode(base.Value); 
                if (node != null
                { 
                    this.pageId = node.CmsPage.ID; 
                    this.linkDefaultText = node.CmsPage.MenuName; 
                } 
     
                this.dependentProps["PageId"] = this.pageId; 
                this.dependentProps["LinkDefaultText"] = this.linkDefaultText; 
            } 
            #region Private Fields 
            private Guid pageId; 
            private string linkDefaultText; 
            private Dictionary<stringobject> dependentProps; 
            #endregion 
        } 
     

    For the moment being it is not possible to pass any parameters from user control that would do this dynamically. However we are planning to introduce custom control designers in Sitefinity 3.1 which will allow you a greater degree of freedom to design controls the way you want them.

    I hope this helps, and once again, I'm really sorry I could not provide you with an answer sooner.

    Thanks,
    Ivan
  14. Jason Grovert
    Jason Grovert avatar
    28 posts
    Registered:
    25 Oct 2005
    08 Jun 2007
    Link to this post

    Hi Ivan,

    Thanks again for your help.  We've decided to go with the seperate class files implementation because we have a couple of User Controls that have multple sets of Properties that have to use this feature with so placing all the logic in one class (control) won't work for us because we won't know at runtime which sets of properties we're editing.  Please keep this in mind as you work on your solution for SiteFinity 3.1.

  15. iosmak
    iosmak avatar
    18 posts
    Registered:
    12 Oct 2006
    08 Jun 2007
    Link to this post
    Hi Jason,

    I'm glad you've find a satisfying solution for the moment being. We've been talking about this and most probably we will provide a solution for sending additional information to web editors from controls in one of the upcoming version.

    I'm sorry that you had to work around this issue and I'd like to thank you for good suggestions and your understanding.

    Thanks,
    Ivan


Register for webinar
15 posts, 0 answered