Query a page for its controls

Posted by Community Admin on 04-Aug-2018 13:20

Query a page for its controls

All Replies

Posted by Community Admin on 17-Jun-2013 00:00

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.

Posted by Community Admin on 18-Jun-2013 00:00

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

Posted by Community Admin on 18-Jun-2013 00:00

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

Posted by Community Admin on 18-Jun-2013 00:00

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.

Posted by Community Admin on 20-Jun-2013 00:00

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

Posted by Community Admin on 20-Jun-2013 00:00

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

Posted by Community Admin on 21-Jun-2013 00:00

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

Posted by Community Admin on 21-Jun-2013 00:00

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

This thread is closed