尝试使用c#构建递归html菜单。我需要的html结构如下:
<ul>
<li>Office</li>
<li>Home
<ul>
<li>Beds</li>
<li>Desks</li>
</ul>
</li>
<li>Outdoor
<ul>
<li>Children
<ul>
<li>Playsets</li>
</ul>
</li>
</ul>
</li>
</ul>
结构可能会因动态而明显改变。目前,我正在使用HtmlGeneric控件,即ul,li和添加控件,但不知道如何将其转换为有效的递归函数。
答案 0 :(得分:3)
我不确定你保留字符串层次结构的结构是什么,但我们假设你有一些方法可以根据需要获取每个字符串的子字符串(例如,你可以从''获得'床'和'桌子'家')。
首先,我将标签声明为常量:
public const string OPEN_LIST_TAG = "<ul>";
public const string CLOSE_LIST_TAG = "</ul>";
public const string OPEN_LIST_ITEM_TAG = "<li>";
public const string CLOSE_LIST_ITEM_TAG = "</li>";
然后我会使用类似字符串构建器的东西创建一个递归方法:
/// <summary>
/// Adds another level of HTML list and list items to a string
/// </summary>
/// <param name="str">The string to add</param>
/// <param name="liStrings">The list of strings at this level to add</param>
/// <param name="iTabIndex">The current number of tabs indented from the left</param>
public void GenerateHTML( System.Text.StringBuilder str, List<string> liStrings, int iTabIndex) {
//add tabs to start of string
this.AddTabs(str, iTabIndex);
//append opening list tag
str.AppendLine(OPEN_LIST_TAG);
foreach (string strParent in liStrings) {
//add tabs for list item
this.AddTabs(str, iTabIndex + 1);
//if there are child strings for this string then loop through them recursively
if (this.GetChildStrings(strParent).Count > 0) {
str.AppendLine(OPEN_LIST_ITEM_TAG + strParent);
GenerateHTML(str, this.GetChildStrings(strParent), iTabIndex + 2);
//add tabs for closing list item tag
this.AddTabs(str, iTabIndex + 1);
str.AppendLine(CLOSE_LIST_ITEM_TAG);
}
else {
//append opening and closing list item tags
str.AppendLine(OPEN_LIST_ITEM_TAG + strParent + CLOSE_LIST_ITEM_TAG);
}
}
//add tabs for closing list tag
this.AddTabs(str, iTabIndex);
//append closing list tag
str.AppendLine(CLOSE_LIST_TAG);
}
将选项卡分开添加到单独的方法中:
/// <summary>
/// Appends a number of tabs to the string builder
/// </summary>
/// <param name="str">The string builder to append to</param>
/// <param name="iTabIndex">The number of tabs to append to</param>
public void AddTabs(System.Text.StringBuilder str, int iTabIndex) {
for (int i = 0; i <= iTabIndex; i++) {
str.Append("\t");
}
}
然后简单地使用新的字符串构建器调用GenerateHTML,第一级字符串和选项卡索引设置为0,它应该为您提供所需的内容。我没有包含获取子字符串的功能,因为我不确定您使用什么样的结构 - 让我知道,我可以调整我的解决方案。
希望有所帮助, 戴恩。
答案 1 :(得分:1)
有点老话题,但它应该有正确答案
在我的示例中,传入的节点包含Children属性,其中包含子元素。
private HtmlGenericControl RenderMenu(Nodes nodes)
{
if (nodes == null)
return null;
var ul = new HtmlGenericControl("ul");
foreach (Node node in nodes)
{
var li = new HtmlGenericControl("li");
li.InnerText = node.Name;
if(node.Children != null)
{
li.Controls.Add(RenderMenu(node.Children));
}
ul.Controls.Add(li);
}
return ul;
}
答案 2 :(得分:0)
关于这样的列表的唯一递归是数据的结构。 NGenerics是一个很好的数据结构开源库。
此外,我建议在此问题中使用HTMLTextWriter Class。
如果你想采用自己动手的方法并创建一个服务器控件,那么下面的类就可以了。
public class MenuTree : Control
{
public string MenuText {get; set;}
public List<MenuTree> Children {get; set;}
public override void Render(HTMLTextWriter writer)
{
writer.RenderBeginTag(HtmlTextWriterTag.Ul);
writer.RenderBeginTag(HtmlTextWriterTag.Li);
writer.RenderBeginTag(MenuText);
writer.RenderEndTag();
foreach (MenuTree m in Children)
{
m.Render();
}
writer.RenderEndTag();
}
}