Query a page for its controls
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.
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
>
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
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.
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);
<%@ 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
>
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
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?
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