-1

Let’s assume I have a Parent/child menu structure like below. How can I loop through the menu to build up the breadcrumbs?

So, for each menu item I would like to build up the breadcrumbs for all its parents. I added the breadcrumb properties in the menu to showcase what I would like to achieve.

Class

public class Menu
{
    public string Text { get; set; }
    public string Action { get; set; }
    public string Area { get; set; }
    public string Controller { get; set; }
    public IEnumerable<Breadcrumb> Breadcrumb { get; set; }
    public List<Menu> Children { get; set; }
}

Menu Implementation

Menu menu = new Menu();
menu.Action = "Index";
menu.Controller = "Home";
menu.Area = "";
menu.Text = "Employees";
//Breadcrumb = new [] { new Breadcrumb() { Text = "Employees", Action = "Index", Controller = "Home"} },
menu.Children = new List<Menu>
{
    new Menu()
    {
        Text = "Payroll Processing",
        //Breadcrumb = new [] { new Breadcrumb() { Text  = "Payroll Processing" }, new Breadcrumb() { Text = "Employees", Action = "Index", Controller = "Home"} },
        // No Route data
        Children = new List<Menu>()
        {
            new Menu()
            {
                Action = "Index",
                Controller = "SomeRandomControllerA",
                Area = "Employees",
                Text = "View",
                //Breadcrumb = new [] { new Breadcrumb() { Text = "View", Action = "Index", Controller = "SomeRandomControllerA", }, new Breadcrumb() { Text  = "Payroll Processing" }, new Breadcrumb() { Text = "Employees", Action = "Index", Controller = "Home"} }
            },
            new Menu()
            {
                Action = "Index",
                Controller = "SomeRandomControllerB",
                Area = "Employees",
                Text = "View",
                //Breadcrumb = new [] { new Breadcrumb() { Text = "View", Action = "Index", Controller = "SomeRandomControllerB", }, new Breadcrumb() { Text  = "Payroll Processing" }, new Breadcrumb() { Text = "Employees", Action = "Index", Controller = "Home"} },
                Children = new List<Menu>()
                {
                    new Menu()
                    {
                        Action = "Index",
                        Controller = "SomeRandomControllerBA",
                        Area = "Employees",
                        Text = "ViewBA",
                        //Breadcrumb = new [] { new Breadcrumb() { Text = "ViewBA", Action = "Index", Controller = "SomeRandomControllerBA", }, new Breadcrumb() { Text = "View", Action = "Index", Controller = "SomeRandomControllerB", }, new Breadcrumb() { Text  = "Payroll Processing" }, new Breadcrumb() { Text = "Employees", Action = "Index", Controller = "Home"} }
                    },
                }
            }
        }
    }
};
R4nc1d
  • 2,923
  • 3
  • 24
  • 44
  • Maybe you mean/need a __recursive__ function to get then modify each Menu object in the tree. – dr.null Oct 03 '20 at 23:19
  • I have tried using recursion but because there is no parent reference in the list it makes it a bit hard. – R4nc1d Oct 04 '20 at 04:16

1 Answers1

1

You need two functions, one to process the parent, and another to process the children of all levels.

Consider the following extension method for the Menu type:

//In the namespace block..
static class Extensions
{
    public static IEnumerable<Menu> GetMenus(this Menu parent)
    {
        IEnumerable<Menu> GetMenus(IEnumerable<Menu> children)
        {
            foreach (var child in children)
            {
                yield return child;

                if (child.Children != null)
                    foreach (var grandChild in GetMenus(child.Children))
                        yield return grandChild;
            }
        }

        yield return parent;

        if (parent.Children != null)
            foreach (var child in GetMenus(parent.Children))
                yield return child;
    }
}

Call it from any instance of the Menu type:

foreach (var m in menu.GetMenus())
    //ToDo: ...;

Or maybe with the Where clause to get specific Menu items:

foreach (var m in menu.GetMenus().Where(x => x.Action == "Index"))
    //ToDo: ...;

You will get an IEnumerable<Menu> includes the parent and all of its children.

Taken from this post.


Edit: Example for the Breadcrumb part.


// I believe the Breadcrumb class is something like:
public class Breadcrumb
{
    public string Text { get; set; }
    public string Action { get; set; }
    public string Controller { get; set; }

    public override string ToString() =>
        $"{Text}, {Action}, {Controller}";
}

// Where you create the Breadcrumb for each Menu object.
var bc = new List<Breadcrumb>();

foreach (var m in menu.GetMenus())
{
    bc.Insert(0, new Breadcrumb
    {
        Text = m.Text,
        Action = m.Action,
        Controller = m.Controller
    });

    m.Breadcrumb = bc.ToArray();

    Console.WriteLine(string.Join(", ", m.Breadcrumb));
}

I get this output:

Employees, Index, Home
Payroll Processing, , , Employees, Index, Home
View, Index, SomeRandomControllerA, Payroll Processing, , , Employees, Index, Home
View, Index, SomeRandomControllerB, View, Index, SomeRandomControllerA, Payroll Processing, , , Employees, Index, Home
ViewBA, Index, SomeRandomControllerBA, View, Index, SomeRandomControllerB, View, Index, SomeRandomControllerA, Payroll Processing, , , Employees, Index, Home

dr.null
  • 4,032
  • 3
  • 9
  • 12
  • I understand how recursion works, I guess the part I don't understand is as i traverse the tree downwards for each menu item i need to traverse the tree upwards to get all the parent values again so that i can build up my breadcrumbs. Or how from your example will you be able create the breadcrumbs i fail to see that? – R4nc1d Oct 04 '20 at 17:59
  • @R4nc1d I see. Many ways to append/prepend the `Breadcrumb` objects of the parents. Check out the edit please. – dr.null Oct 04 '20 at 19:58
  • 1
    Awesome, thanks let me have a look, +1 for your help so far – R4nc1d Oct 04 '20 at 20:16