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

Forums / Developing with Sitefinity / Query a page for its controls

Query a page for its controls

8 posts, 0 answered
  1. Daniel
    Daniel avatar
    5 posts
    Registered:
    14 Jun 2013
    17 Jun 2013
    Link to this post
    Hello,

    I'm hoping this is simple, as I have a need to retrieve a collection of objects (custom widgets in this case) that are inside the current page.

    My need is that I have some (one of more) of ScrollTarget objects (SitefinityWebApp.Widgets.Scrolls.ScrollTarget), and I have another object (again, another ascx file) that I wish to obtain a collection of ScrollTargets that are inside the current page.

    I have tried almost everything I have found on forums or blogs, but still I can't find a way of achieving this.

    In essence, I have the following code:

                    using (var fluent = App.WorkWith())
                    {
                        SiteMapNode currentNode = SiteMap.CurrentNode;
                        if (currentNode != null)
                        {
                            var pm = Telerik.Sitefinity.Modules.Pages.PageManager.GetManager();
                            var page = pm.GetPageNodes().Where(p => p.Id == new Guid(currentNode.Key)).SingleOrDefault();
                            if (page != null)
                            {
                                // Get a list of SitefinityWebApp.Widgets.Scrolls.ScrollTarget objects on this page
                            }
                        }
                    }

    But that final step seems to be a step too far (for me). Can anyone please help, as this seems like a very simple thing, but yet one that appears to be impossible through the API.

    Many thanks.
  2. Peter
    Peter avatar
    36 posts
    Registered:
    03 Oct 2016
    18 Jun 2013
    Link to this post
    Hi Daniel,

    you were very close, so good job! To get the collection of controls, you will need the checked out version of the PageData object. This will give you a collection of PageDraftControl elements, which are the objects that represent the widgets onto the page.

    Please find the code for a custom control below, which gets the type of the page's widgets and renders them in a label:

    using System;
    using System.Linq;
    using System.Web;
    using Telerik.Sitefinity;
    using Telerik.Sitefinity.Modules.Pages;
    using Telerik.Sitefinity.Pages.Model;
     
    namespace SitefinityWebApp.MyControls.ControlCrawler
    {
        public partial class ControlCrawler : System.Web.UI.UserControl
        {
            protected void Page_Load(object sender, EventArgs e)
            {
     
            }
     
            protected void Button1_Click(object sender, EventArgs e)
            {
                using (var fluent = App.WorkWith())
                {
                    SiteMapNode currentNode = SiteMap.CurrentNode;
                    if (currentNode != null)
                    {
                        var pm = PageManager.GetManager();
                        var controls = fluent.Page(new Guid(currentNode.Key)).AsStandardPage().CheckOut().Get().Controls;
                        string controlInfo = string.Empty;
     
                        if (controls != null || controls.Count > 0)
                        {
                            foreach (PageDraftControl pageControl in controls)
                            {
                                controlInfo += string.Format("{0}<br/ >", pageControl.ObjectType);
                            }
                        }
                        Label1.Text += controlInfo;
                    }
                }
            }
        }
    }

    And f course, here is the template of the custom control as well:

    <%@ Control Language="C#" AutoEventWireup="true" CodeBehind="ControlCrawler.ascx.cs" Inherits="SitefinityWebApp.MyControls.ControlCrawler.ControlCrawler" %>
     
    <div>
        <h2>Button Crawler</h2>
        <asp:Button ID="Button1" runat="server" Text="Click To Get Controls" OnClick="Button1_Click" />
        <hr />
        <div>
            <asp:Label ID="Label1" runat="server" Text=""></asp:Label>
        </div>
    </div>
     
    Hope this helps!

    Cheers,
    Peter
    Telerik
    Do you want to have your say in the Sitefinity development roadmap? Do you want to know when a feature you requested is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
  3. Daniel
    Daniel avatar
    5 posts
    Registered:
    14 Jun 2013
    18 Jun 2013 in reply to Peter
    Link to this post
    Hi Peter,

    thank you for this prompt response. I'm away from the project now, but will attempt what you've suggested, and will report back later.

    Just wanted you to know your efforts have been received, and are appreciated.

    Regards,

    Daniel
  4. Daniel
    Daniel avatar
    5 posts
    Registered:
    14 Jun 2013
    18 Jun 2013 in reply to Daniel
    Link to this post
    Hello Peter,

    Ii have managed to get a collection of PageDraftControl items, and have filtered this down to the ones I want, via their ObjectType. However, I now cannot seem to interact with these objects, as i can't convert them back to their Type. Is there a way I can get the properties out of these PageDraftControls?

    I have tried:

    using (var fluent = App.WorkWith())
                    {
                        SiteMapNode currentNode = SiteMap.CurrentNode;
                        if (currentNode != null)
                        {
                            var pm = Telerik.Sitefinity.Modules.Pages.PageManager.GetManager();
                            var controls = fluent.Page(new Guid(currentNode.Key)).AsStandardPage().CheckOut().Get().Controls;
                            if (controls != null && controls.Count > 0)
                            {
                                var navigators = controls.Where(c => c.ObjectType.StartsWith(typeof(ScrollToNavigator).FullName)); //  typeof(ScrollToNavigator).QualifiedObjectType()
                                foreach (PageDraftControl control in navigators)
                                {
                                    //ScrollToNavigator nav = control as ScrollToNavigator; // Cannot convert type 'PageDraftControl' to 'ScrollToNavigator' via a reference conversion, boxing conversion, unboxing conversion, wrapping conversion or null type conversion.

                                    ScrollToNavigator reader = new ScrollToNavigator();
                                    pm.ReadProperties(reader, control); // This doesn't seem to read the properties from object as suggested?

                                }
                            }
                        }
                    }
     
    Thank you.
  5. Peter
    Peter avatar
    36 posts
    Registered:
    03 Oct 2016
    20 Jun 2013
    Link to this post
    Hi Daniel,

    Yes there is definitely a way and I have enhanced my initial sample to include the more advanced logic of interacting with the widget's properties. Please find it below a sample, which gets the ContentBlock widgets dropped onto their pages and get a property by its name ("Html") and changes it using the Property Descriptor's features of Sitefinity.

    First the code behind:
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using Telerik.Sitefinity.Modules.GenericContent.Web.UI;
    using Telerik.Sitefinity.Modules.Pages;
    using Telerik.Sitefinity.Pages.Model;
    using Telerik.Sitefinity.Workflow;
     
    namespace SitefinityWebApp.MyControls.ControlCrawler
    {
        public partial class ControlCrawler : System.Web.UI.UserControl
        {
            protected void Button1_Click(object sender, EventArgs e)
            {
                SiteMapNode currentNode = SiteMap.CurrentNode;
                if (currentNode != null)
                {
                    var pm = PageManager.GetManager();
                    PageNode pageNode = pm.GetPageNode(new Guid(currentNode.Key));
                    var draft = pm.EditPage(pageNode.PageId);
                    if (draft != null)
                    {
                        var controls = draft.Controls.Where(c => c.ObjectType.StartsWith(typeof(ContentBlock).FullName)).DefaultIfEmpty();
                        string controlInfo = string.Empty;
     
                        if (controls != null)
                        {
                            foreach (PageDraftControl pageControl in controls)
                            {
                                controlInfo += string.Format("{0}<br/ >", pageControl.ObjectType);
     
                                Guid contentBlockId = pageControl.Id;
                                ControlProperty htmlProperty = pageControl.Properties.Where(prop => prop.Control.Id == contentBlockId && prop.Name == "Html").FirstOrDefault();
     
                                if (htmlProperty != null)
                                {
                                    controlInfo += string.Format("HTML property is:<div style=\"background-color: gray !important;\">{0}</div>", htmlProperty.Value);
                                    htmlProperty.Value = "I have been changed using the API only! )";
                                }
                            }
                        }
                        Label1.Text += controlInfo;
     
                        pm.PagesLifecycle.CheckIn(draft);
                        pm.SaveChanges();
     
                        // Publish
                        var bag = new Dictionary<string, string>();
                        bag.Add("ContentType", typeof(PageNode).FullName);
                        WorkflowManager.MessageWorkflow(pageNode.Id, typeof(PageNode), null, "Publish", false, bag);
                    }
                }
            }
        }
    }

    Second the markup:
    <%@ Control Language="C#" AutoEventWireup="true" CodeBehind="ControlCrawler.ascx.cs" Inherits="SitefinityWebApp.MyControls.ControlCrawler.ControlCrawler" %>
     
    <div>
        <h2>Button Crawler</h2>
        <asp:Button ID="Button1" runat="server" Text="Click To Get Controls" OnClick="Button1_Click" />
        <hr />
        <div>
            <asp:Label ID="Label1" runat="server" Text=""></asp:Label>
        </div>
    </div>

    Also, here is our documentation on how you can programmatically add or remove controls onto the Sitefinity pages (link here)

    Hope this helps!

    Regards,
    Peter
    Telerik
    Do you want to have your say in the Sitefinity development roadmap? Do you want to know when a feature you requested is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
  6. Daniel
    Daniel avatar
    5 posts
    Registered:
    14 Jun 2013
    20 Jun 2013 in reply to Peter
    Link to this post
    Hello Peter,

    thank you for this. I did, however, find an alternative solution of my own. I went for:

                                var navs = controls.Where(c => c.ObjectType.StartsWith(typeof(ScrollToNavigator).FullName)); 
                                foreach (PageDraftControl control in navs)
                                {
                                    ScrollToNavigator nav = pm.LoadControl(control) as ScrollToNavigator;
                                    navigators.Add(new ScrollToNavigatorData()
                                    {
                                        Title = nav.Title,
                                        Name = nav.Name
                                    });
                                }

    You can ignore most of this, but I've used the pm.LoadControl(control) (from PageManager) and then cast the object to the type I wanted.

    Not sure though, if this is the equivalent of your code? I suspect yours might be more efficient?

    Regards,

    Daniel
  7. Peter
    Peter avatar
    36 posts
    Registered:
    03 Oct 2016
    21 Jun 2013
    Link to this post
    Hi Daniel,

    Based on the things you want to achieve your approach makes perfect sense and I will definitely go for it. The PageManager class inherits from ControlManager<PageDataProvider>, and the goal of that abstract class is to provide API for managing Sitefinity controls.

    My sample gives you a way to edit the controls onto the page and the code goes through workflow, publishing and other heavy tasks, which in your case are not needed and will slow down the execution with things you don't need.

    I mean, based on your last piece of code, it looks like you just want to read control properties, right?

    Regards,
    Peter
    Telerik
    Do you want to have your say in the Sitefinity development roadmap? Do you want to know when a feature you requested is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
  8. Daniel
    Daniel avatar
    5 posts
    Registered:
    14 Jun 2013
    21 Jun 2013 in reply to Peter
    Link to this post
    Yes Peter, I just wanted to read the control's properties.

    I'll leave my code as it is then. Thank you so much for giving me the code to obtain the page's controls though, this was invaluable.

    Regards,

    Daniel
8 posts, 0 answered