2009-09-08 5 views
2

Попытка создать рекурсивное html-меню с помощью C#. Мне нужна следующая структура html:Рекурсивный конструктор меню с C#

<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

Пожалуйста, добавьте код, который у вас есть на моменте. – Owen

+1

Какую структуру вы используете для хранения строк (например, «Главная», «Кровати», «Столы» и т. Д.)? – link664

ответ

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, и он должен дать вам то, что вы хотите. Я не включил функции, чтобы получить дочерние строки, поскольку я не был уверен, какую структуру вы используете для этого - дайте мне знать, и я смогу адаптировать свое решение.

Надеюсь, что это поможет, Dane.

0

Единственное, что рекурсивно относится к подобному списку, это srtructure данных. 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(); 
    } 


} 
1

Немного старая тема, но тем не менее он должен иметь правильный ответ

В моем примере входящих узлы содержат свойство Детей, которые содержат дочерние элементы.

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; 
} 
+0

хороший. Я смотрел что-то подобное. – Nakres

Смежные вопросы