ASP Control unordered list UL with nested list - c#

I tried Menu, TreeView, BulletedList, Repeater, HtmlGenericControl but without result.
What I would like to have is asp control which render something:
<ul>
<li>Item 1</li>
<li>Item 2
<ul>
<li>Item 2.1</li>
</ul>
</li>
</ul>
For example menu it's render SPAN no UL.
<asp:Menu runat="server">
<Items>
<asp:MenuItem Text="Item 1" />
<asp:MenuItem Text="Item 2">
<asp:MenuItem Text="Item 2.1" />
</asp:MenuItem>
</Items>
</asp:Menu>
I also tried
<asp:Menu RenderingMode="MenuRenderingMode" />
But it's not working. I'm using ASP.NET 3.5.
I need create dynamic ul list and after click on item it will check in db if exist nested items and add them to clicked list as nested ul.
I cant render whole menu at once because of performence.
Sorry if I'm not very clear.
Thanks for help.

You need to use nested repeaters:
<asp:Repeater ID="rptFoo" runat="server" OnItemDataBound="rptFoo_ItemDataBound">
<HeaderTemplate>
<ul>
</HeaderTemplate>
<ItemTemplate>
<li>
<asp:HyperLink ID="lnkFoo" runat="server" />
<asp:Repeater ID="rptBar" runat="server" OnItemDataBound="rptBar_ItemDataBound">
<HeaderTemplate>
<ul>
</HeaderTemplate>
<ItemTemplate>
<li><asp:HyperLink ID="lnkBar" runat="server" /></li>
</ItemTemplate>
<FooterTemplate>
</ul>
</FooterTemplate>
</asp:Repeater>
</li>
</ItemTemplate>
<FooterTemplate>
</ul>
</FooterTemplate>
</asp:Repeater>
And then in the ItemDataBound handler, you need to check whether each top level item has child elements, if it does, assign those elements to the sub repeater and databind, else hide it.
protected void rptFoo_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if ((e.Item.ItemType == ListItemType.Item) || (e.Item.ItemType == ListItemType.AlternatingItem))
{
FooType obj = (FooType)e.Item.DataItem;
Repeater rptBar = (Repeater)e.Item.FindControl("rptBar");
if(obj.Children.Count() > 0)
{
rptBar.DataSource = obj.Children;
rptBar.DataBind();
}
else
{
rptBar.Visible = false;
}
}
}

If you just need access to the ul and li elements from codebehind you can easily add a runat="server" attribute to them. The id attribute is necessary in order to be able to reference a single element:
<ul id="mainMenu" runat="server">
<li id="mainMenuItem1" runat="server">Item 1</li>
<li id="mainMenuItem2" runat="server">Item 2
<ul id="subMenu" runat="server">
<li id="subMenuItem1" runat="server">Item 2.1</li>
</ul>
</li>
</ul>
This structure could also be build from codebehind using HtmlGenericControls.
Another option could be to use user controls: http://msdn.microsoft.com/en-us/library/y6wb1a0e%28v=vs.100%29.aspx

Related

how to access a header template in c#

I have a template:
<asp:Repeater ID="litFolder" runat="server" OnItemDataBound="litFolder_ItemDataBound">
<HeaderTemplate>
<ul class="test" id="currentLink">
</HeaderTemplate>
<ItemTemplate>
<div class="leftNav">
<li>
<asp:HyperLink ID="innerHyperLink" runat="server"></asp:HyperLink>
</li>
</div>
</ItemTemplate>
<FooterTemplate>
</ul>
</FooterTemplate>
</asp:Repeater>
and I'm trying to set the to display block when a link is selected. I can set the link to display block, but how do I set the ul to display block ( only using C# )
protected void litFolder_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
// if the child from the first repeater has children, it will grab them here
Item innerItem = (Item)e.Item.DataItem;
if (innerItem != null)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
// this creates a link to the page in sitecore once clicked
HyperLink topNavigation = (HyperLink)e.Item.FindControl("innerHyperLink");
topNavigation.NavigateUrl = LinkManager.GetItemUrl(innerItem);
topNavigation.Text = innerItem["Title"];
if (topNavigation != null) {
//this is where I think I need to define the ul to display block
}
}
}
}
I need to make sure that the current link sets the ul that it is in and not all the ul's with the class test.
In order to prevent the Ul from being broken, place the <div class="leftNav"> inside the <li> as shown below:
<asp:Repeater ID="litFolder" runat="server" OnItemDataBound="litFolder_ItemDataBound">
<HeaderTemplate>
<ul class="test" id="currentLink">
</HeaderTemplate>
<ItemTemplate>
<li>
<div class="leftNav">
<asp:HyperLink ID="innerHyperLink" runat="server"></asp:HyperLink>
</div>
</li>
</ItemTemplate>
<FooterTemplate>
</ul>
</FooterTemplate>
To set the display block style, you can find the control based on the ID, then set the style to it.
Thanks

Masterpage controllist only returns some controls

I have a little problem with my ASP.Net Page.
I'm trying to get all controls from my masterpage within the masterpage code.
I did this with the Child page using this code
foreach (Control ctrl in ContentPlaceHolder1.Controls)
{
if (ctrl.GetType() == typeof(Label))
{
//Do Stuff...
}
}
but when i try to get the other controls with
foreach (Control ctrl in this.form1.Controls)
it doesn't work completly.
I get 3 of my Labels but can't access the rest.
Here is a part of my ASP Code
<div style="float: right;">
<ul class="main-language language-level main-language-level-0" >
<li><a href="">
<asp:Label runat="server" Text="Deutschland" ID="lbl_Language"/>
</a>
<ul class="language-level main-language-level-1">
<li>
<a href="?Lng=EN">
<asp:Label ID="lbl_English" runat="server" Text="United Kingdom" ForeColor="#0D679C" Font-Names="Century Gothic" />
</a>
<span>English</span>
</li>
<li>
<a href="?Lng=DE">
<asp:Label ID="lbl_German" runat="server" Text="Deutschland" ForeColor="#0D679C" Font-Names="Century Gothic" />
</a>
<span>Deutsch</span>
</li>
</ul>
<img class="menu-image" src="Images/arrow_languageselection.png" />
</li>
</ul>
<br />
<a href="CustomerServiceLogin.aspx?Lgn=22TR" runat="server" id="LogLink">
<asp:Label CssClass="ButtonOrange" runat="server" ID="lbl_Login" />
<asp:Label CssClass="ButtonOrange" runat="server" ID="lbl_Logoff" Visible="false" />
</a>
</div>
The only labels i can find are lbl_Language,lbl_English and lbl_German
Has somebody a solution for this?
Sincerely
CarnVanBeck
If the labels that you cannot access are nested inside another control then they will not be returned when you iterate over form1.controls. You will need a recursive solution to return all of your controls.
foreach (Control ctrl in this.form1.Controls)
{
if (ctrl.Controls.Count > 0)
{
// do recursive call
}
}

access ascx.cs public bool in ascx html

I am trying to access a public bool in the html piece of a custom user control. Here is a portion of my codebehind:
public partial class ToDoList : System.Web.UI.UserControl
{
public bool ShowAddNewButton { get; set; }
public bool CreateMode { get;set;}
protected void Page_Load(object sender, EventArgs e)
{
}
}
Here is my html:
<%# Control Language="C#" AutoEventWireup="True" CodeBehind="ToDoList.ascx.cs" Inherits="ToDoList" %>
<div id="leftNav">
<asp:HiddenField ID="hfNAVItems" runat="server" />
<asp:HiddenField ID="hfRequestID" runat="server" />
<asp:HiddenField runat="server" ID="hdnAllowDragDrop" />
<div class='nav-header'>
<div>
My To-Do List</div>
</div>
<ul id="mainNav" class="nav-item-list">
<li class="nav-item" id="firstNavContainer">
<div>
<span class="nav-item-todos">
<asp:Label Text="" runat="server" ID="lblfirstSectionHeader" /></span>
<% if(ShowAddNewButton)
{ %>
<asp:Button ID="Button1" runat="server" Text="Add New" CssClass="navaddnewrequest todo-button"
OnClick="btnNewToDo_Click" />
<%} %>
</div>
<ul id="todosNav">
<% if (CreateMode)
{ %>
<li class="SelectedNavHeader">New Todo</li>
<% } %>
<asp:Repeater runat="server" ID="rptToDoNavItems">
<ItemTemplate>
<li class="ToDoSelectedNavGroup" runat="server" id="liToDoNavGroupCont">
<asp:Literal runat="server" ID="lblToDoNavGroupDisplay" /></li>
</ItemTemplate>
</asp:Repeater>
</ul>
</li>
</ul>
<ul id="lineItemNav">
<li class="darkgradient header">My Lists</li>
</ul>
</div>
I am getting the following errors:
The name 'ShowAddNewButton' does not exist in the current context
The name 'CreateMode' does not exist in the current context
scratching my head on this one... seems pretty elemental. Would be happy to learn that I am missing something completely obvious.
Thanks in advance
An alternative method to manage this is using Visible property. You'll need to set your li as runat="server"
<asp:Button ID="Button1" runat="server" Text="Add New" CssClass="navaddnewrequest todo-button"
OnClick="btnNewToDo_Click" Visible='<%= ShowAddNewButton %>'/>
....
<li ID="liNewTodo" runat="server" class="SelectedNavHeader"
Visible='<%= CreateMode %>'>New Todo</li>
If memory serves, you can't really mix code-behind properties and server-side script. You have to pick one. But it's been a long time since I tried it, so maybe you can.
It seems to me that, assuming you can do it, the problem is that the server-side script is interpreting your property names as variable names. You could try prefixing them with this or base and seeing if that helps.

Change value of databound control within Repeaters in C#

I have a nested repeater control that displays a list of data, in my case it is an FAQ list. here is the design portion:
<asp:Repeater ID="lists" runat="server">
<ItemTemplate>
<h2 class="sf_listTitle"><asp:Literal ID="listTitle" runat="server"></asp:Literal></h2>
<p class="sf_controlListItems">
<a id="expandAll" runat="server">
<asp:Literal ID="Literal1" runat="server" Text="<%$Resources:ExpandAll %>"></asp:Literal>
</a>
<a id="collapseAll" runat="server" style="display:none;">
<asp:Literal ID="Literal2" runat="server" Text="<%$Resources:CollapseAll %>"></asp:Literal>
</a>
</p>
<ul class="sf_expandableList" id="expandableList" runat="server">
<asp:Repeater ID="listItems" runat="server">
<HeaderTemplate>
</HeaderTemplate>
<ItemTemplate>
<li>
<h1 id="headlineContainer" runat="server" class="sf_listItemTitle">
<a id="headline" runat="server" title="<%$Resources:ClickToExpand %>"></a>
</h1>
<div id="contentContainer" runat="server" class="sf_listItemBody" style="display:none;">
<asp:Literal ID="content" runat="server"></asp:Literal>
</div>
</li>
</ItemTemplate>
<FooterTemplate>
</FooterTemplate>
</asp:Repeater>
</ul>
</ItemTemplate>
</asp:Repeater>
The repeater that I am interested in is the second repeater, listItems. In my code-behind, I cannot directly call listItems and see the controls inside of it. I tried to grab the control inside of list.DataBinding (maybe I need to use a different event?) method:
void lists_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
var oRepeater = (Repeater) lists.FindControl("listItems");
}
but this comes up as null. Can anyone give me some pointers/tips of what I need to do to gain access to the listItems repeater and it's children controls?
Thanks!
lists
belongs to each RepeaterItem, not directly to the Repeater itself.
Try :-
void lists_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if ( e.Item.ItemType == ListItemType.AlternatingItem
|| e.Item.ItemType == ListItemType.Item )
{
Repeater oRepeater = (Repeater)e.Item.FindControl("listItems");
// And to get the stuff inside.
foreach ( RepeaterItem myItem in oRepeater.Items )
{
if ( myItem.Item.ItemType == ListItemType.AlternatingItem
|| myItem.Item.ItemType == ListItemType.Item )
{
Literal myContent = (Literal)myItem.FindControl("content");
// Do Something Good!
myContent.Text = "Huzzah!";
}
}
}
}
And you should be good :)
Edited to incorporate DavidP's helpful refinement.
You need to change that line to
var oRepeater = (Repeater) e.Item.FindControl("listItems");
You're close! Inside your event handler check the RepeaterItemEventArgs for what kind of row you're dealing with. Your child repeater will only be available on (Alt)Item rows, not headers or footers. My guess is that it's blowing up on the header.

populate a html list control using .NET

I have a list defined like so:
<ul id="myList" class='myClass'>
<li class="myItemClass">Item 1</li>
<li class="myItemClass">Item 2</li>
</ul>
using .NET how can I add items to the list dynamically? I also need to specify the class name on each new item
you can even use that HTML, adding runat="server" you will be able to treat it as a HTMLControl no mater what control it is, I do this often with div's
<ul id="myList" runat="server" class="myClass">
<li class="myItemClass">Item 1</li>
<li class="myItemClass">Item 2</li>
</ul>
then you get that HTMLControl and play with it
HtmlGenericControl li;
for (int x = 3; x <= 10; x++)
{
li = new HtmlGenericControl("li");
li.Attributes.Add("class", "myItemClass");
li.InnerText = "Item " + x;
myList.Controls.Add(li);
}
you will end up with:
<ul id="myList" runat="server" class="myClass">
<li class="myItemClass">Item 1</li>
<li class="myItemClass">Item 2</li>
<li class="myItemClass">Item 3</li>
<li class="myItemClass">Item 4</li>
<li class="myItemClass">Item 5</li>
<li class="myItemClass">Item 6</li>
<li class="myItemClass">Item 7</li>
<li class="myItemClass">Item 8</li>
<li class="myItemClass">Item 9</li>
<li class="myItemClass">Item 10</li>
</ul>
of course that you can use an ordered or unorderer list, they also below to the ASP.NET Web Controls.
<asp:BulletedList runat="server" ...
You could use asp:BulletedList like
<asp:BulletedList ID="MyList1" CssClass="MyClass" runat="server">
<asp:ListItem Text="Item1" class="MyClass" />
</asp:BulletedList>
Add add code like
ListItem item = new ListItem("Item2");
item.Attributes.Add("class", "MyClass");
MyList1.Items.Add(item);
Or if for some specific reason you need to use the ul tag then you can add a runat="server" to it. E.g.
<ul id="MyList2" class="MyClass" runat="server">
<li class="MyClass">Item1</li>
</ul>
With code like
HtmlGenericControl li = new HtmlGenericControl("li");
li.Attributes.Add("class", "MyClass");
li.InnerText = "Item2";
MyList2.Controls.Add(li);
The simplest way you can solve this problem is by using the asp repeater control
<ul id="myList" class='myClass'>
<asp:Repeater ID="repeaterMyList" Runat="server">
<ItemTemplate>
<li class="myItemClass">
<%# Eval("Item") %>
</li>
</ItemTemplate>
</asp:Repeater>
</ul>
[Edit] - Do remember to set the datasource on repeaterMyList and call databind on the repeater control in the codebehind.
repeaterMyList.DataSource = someDataTable;
repeaterMyList.DataBind();
I'm assuming that there is a valid reason for you not to use the BulletedList webserver control. Anyway, this is an interesting programming exercise that illustrates the internals of the Htmlservercontrol architecture and how they map to simple HTML tags.
The HTML ul and li tags are not directly mapped as HTMLServercontrols. This means that even if you add a runat="server" attribute to the list, it's contents will not be directly accessible as listitems.
However, all controls not directly mapped as Html server controls are accessible via the HtmlGenericControl class. This makes it possible to create and modify such controls dynamically.
The solution, therefore, is twofold:
Make the unordered list runat="server" so that you can access it in server-side code. Also, you should make the existing items in the list runat="server", else they will be only be accessible as an LiteralControl that contains the first two listitems as plain text.
In code, access the contents of the list and add a new HtmlGenericControl of type "li" to it.
The following (bare-bones simple) page demonstrates this procedure :
<%# Page Language="VB" AutoEventWireup="false" %>
<%# Import Namespace="System.Collections.Generic" %>
<script runat="server">
Private Shared addedItems As List(Of HtmlGenericControl)
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not Page.IsPostBack Then
'On first load, instantiate the List.
addedItems = New List(Of HtmlGenericControl)
End If
End Sub
Protected Sub btn1_Click(ByVal sender As Object, ByVal e As System.EventArgs)
'Add the previously created items to the UL list.
'This step is necessary because
'...the previously added items are lost on postback.
For i As Integer = 0 To addedItems.Count - 1
myList.Controls.Add(addedItems.Item(i))
Next
'Get the existing no. of items in the list
Dim count As Integer = myList.Controls.Count
'Create a new list item based on input in textbox.
Dim li As HtmlGenericControl = CreateBulletItem()
'Add the new list item at the end of the BulletedList.
myList.Controls.AddAt(count, li)
'Also add this newly created list item to the generic list.
addedItems.Add(li)
End Sub
Private Function CreateBulletItem() As HtmlGenericControl
Dim li As New HtmlGenericControl("li")
li.InnerText = txtNewItem.Value
li.Attributes("class") = "myItemClass"
Return li
End Function
</script>
<html>
<head runat="server">
<title>Test Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<ul id="myList" class='myClass' runat="server">
<li runat="server" class="myItemClass">Item 1</li>
<li runat="server" class="myItemClass">Item 2</li>
</ul>
<input type="text" id="txtNewItem" runat="server" />
<asp:Button ID="btn1" runat="server" Text="Add" OnClick="btn1_Click" />
</div>
</form>
</body>
</html>

Categories