Custom Menu using Repeater
I have a custom control in which I am trying to render a menu using a repeater and a nested repeater. When I run it something is happening as a result of the nested repeater and it's databinding. I'm fairly sure the template is right as it was taken from an MSDN article.
Error
InvalidOperationException: Cannot convert from string.]
Telerik.Sitefinity.Web.UI.Templates.Attribute..ctor(String name, String value, ObjectBuilder builder, PropertyDescriptorCollection properties) +1350
Telerik.Sitefinity.Web.UI.Templates.TemplateParser.CreateObjectBuilder(HtmlChunk chunk) +414
Telerik.Sitefinity.Web.UI.Templates.TemplateParser.ParseChunk(HtmlChunk chunk) +75
Telerik.Sitefinity.Web.UI.Templates.TemplateParser.Parse() +187
The Control
public partial class CustomNavigationControl : SimpleView
protected override string LayoutTemplateName
get
return CustomNavigationControl.layoutTemplateName;
protected override void InitializeControls(Telerik.Sitefinity.Web.UI.GenericContainer container)
// base.InitializeControls(container);
private const string layoutTemplateName = "JHFControls.Resources.Views.CustomNavigationControl.ascx";
<%@ Control Language="C#" %>
<
asp:Repeater
runat
=
"server"
ID
=
"menu"
DataSourceID
=
"SiteMapDataSource1"
>
<
HeaderTemplate
>
<
ul
id
=
"topnav"
>
</
HeaderTemplate
>
<
ItemTemplate
>
<
li
>
<
asp:HyperLink
ID
=
"HyperLink1"
runat
=
"server"
NavigateUrl='<%# Eval("Url") %>'><%# Eval("Title") %></
asp:HyperLink
>
<
asp:Repeater
ID
=
"submenu"
runat
=
"server"
DataSource='<%# ((SiteMapNode) Container.DataItem).ChildNodes %>'>
<
HeaderTemplate
>
<
ul
>
</
HeaderTemplate
>
<
ItemTemplate
>
<
li
>
<
asp:HyperLink
ID
=
"HyperLink2"
runat
=
"server"
NavigateUrl='<%# Eval("Url") %>'><%# Eval("Title") %></
asp:HyperLink
>
</
li
>
</
ItemTemplate
>
<
FooterTemplate
>
</
ul
>
</
FooterTemplate
>
</
asp:Repeater
>
</
li
>
</
ItemTemplate
>
<
FooterTemplate
>
</
ul
>
</
FooterTemplate
>
</
asp:Repeater
>
<
asp:SiteMapDataSource
ID
=
"SiteMapDataSource1"
runat
=
"server"
ShowStartingNode
=
"false"
ViewStateMode
=
"Disabled"
/>
Hello Dallas,
Remove the comment from base.InitializeControls(container)
protected override void InitializeControls(Telerik.Sitefinity.Web.UI.GenericContainer container)
// base.InitializeControls(container);
Error 1 Cannot call an abstract base member:
'Telerik.Sitefinity.Web.UI.SimpleView.InitializeControls(Telerik.Sitefinity.Web.UI.GenericContainer)'
Hi Dallas,
OK, yes you should not call the base when you inherit from SimpleView. Have you set CustomNavigationControl
.ascx Build Action as "Embed Resource"? Can you remove the code inside <ItemTemplate> from both the Repeaters to see whether the error will appear.
Regards,
Ivan Dimitrov
the Telerik team
The control is an embedded resource. The error occurs on the second binding.
<
asp:Repeater
ID
=
"submenu"
runat
=
"server"
DataSource='<%# ((SiteMapNode) Container.DataItem).ChildNodes %>'>
Hello Dallas Beek,
Sitefinity uses its own parser for parsing embedded resources. Compared to the ASP.NET parser, this parser has limited capabilities for parsing C# code. In the case with your template code, the non-parsable expression is,
<%# ((SiteMapNode) Container.DataItem).ChildNodes %>
<%@ Control Language="C#" %>
<
asp:Repeater
runat
=
"server"
ID
=
"menu"
DataSourceID
=
"SiteMapDataSource1"
>
<
HeaderTemplate
>
<
ul
id
=
"topnav"
>
</
HeaderTemplate
>
<
ItemTemplate
>
<
li
>
<
asp:HyperLink
ID
=
"HyperLink1"
runat
=
"server"
NavigateUrl='<%# Eval("Url") %>'><%# Eval("Title") %></
asp:HyperLink
>
<
asp:Repeater
ID
=
"submenu"
runat
=
"server"
>
<
HeaderTemplate
>
<
ul
>
</
HeaderTemplate
>
<
ItemTemplate
>
<
li
>
<
asp:HyperLink
ID
=
"HyperLink2"
runat
=
"server"
NavigateUrl='<%# Eval("Url") %>'><%# Eval("Title") %></
asp:HyperLink
>
</
li
>
</
ItemTemplate
>
<
FooterTemplate
>
</
ul
>
</
FooterTemplate
>
</
asp:Repeater
>
</
li
>
</
ItemTemplate
>
<
FooterTemplate
>
</
ul
>
</
FooterTemplate
>
</
asp:Repeater
>
<
asp:SiteMapDataSource
ID
=
"SiteMapDataSource1"
runat
=
"server"
ShowStartingNode
=
"false"
ViewStateMode
=
"Disabled"
/>
public
partial
class
CustomNavigationControl : SimpleView
protected
override
string
LayoutTemplateName
get
return
CustomNavigationControl.layoutTemplateName;
protected
override
void
InitializeControls(Telerik.Sitefinity.Web.UI.GenericContainer container)
container.GetControl<Repeater>(
"menu"
,
true
).ItemDataBound +=
new
RepeaterItemEventHandler(CustomNavigationControl_ItemDataBound);
// base.InitializeControls(container);
void
CustomNavigationControl_DataBinding(
object
sender, EventArgs e)
void
CustomNavigationControl_ItemDataBound(
object
sender, RepeaterItemEventArgs e)
if
(e.Item.ItemType.ToString() ==
"Item"
)
var secondRepeater = e.Item.FindControl(
"submenu"
)
as
Repeater;
secondRepeater.DataSource = ((SiteMapNode)e.Item.DataItem).ChildNodes;
secondRepeater.DataBind();
private
const
string
layoutTemplateName =
"Telerik.Sitefinity.Resources.Templates.PublicControls.CustomNavigationControl.ascx"
;
Thank you for replying, your answer to the parsing is what I assumed. I worked through it by creating a new sitemapdatasource as below.
<%@ Control Language="C#" %>
<
asp:SiteMapDataSource
ID
=
"SiteMapDataSource1"
runat
=
"server"
ShowStartingNode
=
"false"
ViewStateMode
=
"Disabled"
/>
<
asp:Repeater
runat
=
"server"
ID
=
"menu"
DataSourceID
=
"SiteMapDataSource1"
>
<
HeaderTemplate
>
<
div
class
=
"pageListWrap"
>
<
h1
>
<
asp:HyperLink
ID
=
"HyperLink1"
runat
=
"server"
NavigateUrl='<%# Eval("Url") %>'><%# Eval("Title") %></
asp:HyperLink
>
</
h1
>
</
HeaderTemplate
>
<
ItemTemplate
>
<
asp:SiteMapDataSource
ID
=
"SiteMapDataSource2"
runat
=
"server"
ShowStartingNode
=
"False"
StartingNodeUrl='<%# Eval("Url") %>' ViewStateMode="Disabled" />
<
asp:Repeater
runat
=
"server"
ID
=
"menu"
DataSourceID
=
"SiteMapDataSource2"
>
<
ItemTemplate
>
<
li
>
<
asp:HyperLink
ID
=
"HyperLink2"
runat
=
"server"
NavigateUrl='<%# Eval("Url") %>'><%# Eval("Title") %></
asp:HyperLink
>
</
li
>
</
ItemTemplate
>
</
asp:Repeater
>
</
ItemTemplate
>
<
FooterTemplate
>
</
div
>
</
FooterTemplate
>
</
asp:Repeater
>