Recursion in C# - c#

I have an object of a custom type I've made (Menu) which can contain child elements of the same type, which naturally can contain child elements and so on.
I wish to generate menus and submenus out of these objects, but I'm wondering how I can traverse them recursively so that I don't have to hard code all my loops. I am a stranger to recursion, is anyone able to shed some light on how to traverse the Menu object and all the underlying objects?
Example code:
public class Menu {
public int MenuID { get; set; }
public int Name { get; set; }
public Menu[] _ChildMenus { get; set; }
}

Here is one option:
private void TraverseMenu(Menu menu)
{
Output(string.Format("Now reading menu #{0}, named {1}", menu.MenuID, menu.Name));
if (menu._ChildMenus != null)
{
foreach (Menu child in menu._ChildMenus)
{
TraverseMenu(child);
}
}
}
If you need to know how "deep" each menu is nested you can add a level parameter:
private void TraverseMenu(Menu menu, int level)
{
Output(string.Format("Now reading menu #{0}, named {1} in level {2}", menu.MenuID, menu.Name, level));
if (menu._ChildMenus != null)
{
foreach (Menu child in menu._ChildMenus)
{
TraverseMenu(child, level + 1);
}
}
}
private void TraverseMenu(Menu menu)
{
TraverseMenu(menu, 0);
}

For rendering purpose you can use partial views.
-- MenuView.cshtml
#model IEnumerable<Menu>
#if (Model != null && Model.Any())
{
<ul>
#foreach(var menu in Model)
{
<li>
<a href='some/path/to/menu?id=#menu.MenuID'>#menu.Name</a>
#Html.RenderPartial("MenuView", menu._ChildMenus)
</li>
}
<ul>
}
EDIT: Since topic changed from something related to MVC from "Recursion in C#", this may seem a little bit irrelevant.

Normally each level of the menu needs a different loop associated with it, for example the first level (eg: home, products, about_us) would display horizontally accross the top, the second level would appear in drop downs beneath the relevant parent menu-item, tertiary levels will appear below the 2nd level menu-item etc..
So for the loops you'd theoretically wan't to split them by level, while maintaining a link back to the parent menu-item so they can be shown. Another more general thing is that the highest menu in the tree is often ignored as a container element for other menu items, this allows you to have more than 1 top level menu something like the following:
EDIT: Fixed the code.. feel free to turn back the edit history to find out how epically non-genius I am :p
string html;
int lastLevel = 0;
void placeMenu( Menu menu, int level)
{
// if level hasn't changed close last menu-item
if( lastLevel == level ) html += "</li>";
// if we're deeper, open a new <UL>
else if( lastLevel < level ) html += "<ul>";
// if we're less deep, close the last <UL> and it's parent menu-item
else if( lastLevel > level ) html += "</ul></li>";
// add current menu item without closing it's <LI> so the next itteration of the loop can add a submenu if needed
html += "<li><a href='http://link/to/page'>" + menu.Name + "</a>";
lastLevel = level;
}
void setupMenu( Menu menu, int level )
{
foreach( var currentMenu in menu._ChildMenus )
{
// place current menu
placeMenu( currentMenu, level + 1 );
// place submenus
setupMenu( currentMenu, level + 1 );
}
}
string setupWholeMenu( Menu menu )
{
setupMenu( menu, 0 );
// close any elements left open by the recursive loop
html = html + "</li></ul>";
return html;
}
this code is designed to make a normal html unordered-level list from your menu structure, this is the standard way to add and style menus in HTML, when you have your menu in this format check out some of these resources to style your menu. The reason to use HTML unordered lists here is that when implemented correctly this list structure will still show up if Javascript & CSS are dissabled (GSM & screen-readers for the partially sighted) and still work in everything IE6+ if Javascript is dissabled.
100 Great CSS Menu Tutorials
CSS Menu maker
Suckerfish dropdowns (where I first learnt how to make CSS menus)
To be honest though in MVC it's usually allot easier just to setup your menu in a declarative way as an unordered list in HTML directly, you can then style it in multiple ways if you place it in a partial shared page or show it everywhere by defining it in your Layout page. This approach can still work if you have a dynamic menu structure as it would seem above, only you'd build the list with Razor which is probably easier too.
Another point of note is that in this kind of recursive function you should use StringBuilder as it's way more efficient then concatenating strings. However for a menu structure (containing up to say 30 items each built with 2-3 concats) this won't cause any notable delay, just something to keep in mind for the future.

Related

Linked list Advice

I've been given a task as follows:
I'd like to to build an implementation of a Linked List. Specifically I'd like it to be a doubly linked list.
My task:
Your program should use the linked list to model a train route using the linked list.
First the user will enter as many stops as they'd like the train to have, and the name of each stop.
The program should then print a map of the route.
Once finished they then enter the name of the stop they want to start at.
From there they can enter commands to move the train either forward to the next stop or backward to the previous one.
I've been told I'm not doing this task right but I don't really understand how not, I'd appreciate it if someone could explain what I'm not doing that I should be doing.
My Route class (it isn't finished but it would've been nearly finished if it was done correctly):
namespace TrainRoute
{
class Route
{
Stops root;
public LinkedList<Stops> linkedList = new LinkedList<Stops>();
public Stops MakeNewStop(string stopName)
{
Stops stopWithStopName = new Stops(stopName);
return stopWithStopName;
}
public void AddStops(Stops stopIWantToAdd)
{
if (linkedList.Count == 0)
{
linkedList.AddFirst(stopIWantToAdd);
}
else
{
//stopIWantToAdd.prevStop = linkedList.Last();
linkedList.AddLast(stopIWantToAdd);
}
}
public void StopRelationships()
{
for (int i = 0; i < linkedList.Count; i++)
{
if (linkedList.ElementAt<Stops>(i).nextStop == null && linkedList.ElementAt<Stops>((i + 1)) != null)
{
linkedList.ElementAt<Stops>(i).nextStop = linkedList.ElementAt<Stops>((i + 1));
}
if (linkedList.ElementAt<Stops>((i - 1)) != null)
{
linkedList.ElementAt<Stops>(i).prevStop = linkedList.ElementAt<Stops>(i - 1);
}
}
}
public void Print()
{
if (linkedList != null)
{
foreach (var item in linkedList)
{
Console.WriteLine("Stop name: " + item.stopName);
}
}
}
public int StopPosition(string usersInput)
{
int position = 0;
for (int i = 0; i < linkedList.Count; i++)
{
if (linkedList.ElementAt<Stops>(i).stopName == usersInput)
{
position = i;
break;
}
}
return position;
}
public int MoveForward(int indexPosition)
{
Console.WriteLine("The train is now at " +linkedList.ElementAt<Stops>(indexPosition).nextStop.stopName);
return (indexPosition + 1);
}
public int MoveBackwords(int indexPosition)
{
Console.WriteLine("The train is now at " + linkedList.ElementAt<Stops>(indexPosition).prevStop.stopName);
return (indexPosition - 1);
}
public bool VerifyRoute(int indexPosition, string prevOrForward)
{
if (prevOrForward.Contains("forward"))
{
if (linkedList.ElementAt<Stops>((indexPosition+1)) != null)
{
return true;
}
}
else
{
if (linkedList.ElementAt<Stops>((indexPosition-1)) != null)
{
return true;
}
}
return false;
}
}
}
I'm also not allowed to use the Linked list class but I'm to use a linked list (I'm not 100% sure what that means).
Any and all advice/help provided will be appreciated!
Let's piece together the breadcrumbs here:
I'd like to to build an implementation of a Linked List.
and this:
I'm also not allowed to use the Linked list class
Obviously the task here is for you to implement your own linked list (class), and not to use the existing one provided by .NET.
I'm assuming here the task is not to build the program handling the trains, but instead to learn how a linked list works, and how you would go about implementing one.
As such, your shortcut to simply grab the existing class is the wrong tool for the job. It would be perfect (probably) if your task was to build that program, but in this case the program is orthogonal to your task, it's there to create a context for what you're really asked to do:
Implement your own version of LinkedList<T> (though you probably don't need to make it generic).
Wikipedia has a very good article on linked lists if you're stumped on how such a data structure really works. There's undoubtedly other very good resources out on the net as well, and probably in your text book or other resources.
Additionally, I would urge you to find a classmate to peer with, from experience I can say that most of the really hard problems I've had in my programming career has (usually) been solved by having a sparring partner to work with.
Implementing a linked list isn't that difficult. I assume you have a textbook and it discusses linked list, read it, carefully. Also you want to clarify with your tutor exactly how much functionality your linked list needs to implement.
Basically, you'll start with a node class, if you don't need it to be generic, then you can create a StopNode class. The basics of your node class will be a reference to the next node in the list and, since this is a doubly linked list, a reference to the previous node:
public class StopNode
{
public StopNode Next { get; set; }
public StopNode Previous { get; set; }
// whatever other properties your stop class needs - such as name
}
Now your LinkedList class will manage the collection of stop nodes. It will need to keep a reference to the first or "head" node and probably the last node too (or "tail").
public class StopLinkedList
{
private StopNode Head { get; }
private StopNode Tail { get; }
}
And it will need to implement methods to add and remove nodes (at a minimum) and probably also insert.
Add is pretty easy - check if Head is null. If it is, just set Head and Tail both equal to your new node. If it's not, you will instead set the Next property of your Tail to your new node, then set the Previous of your new node to the Tail and then finally update your Tail to reference your new node.
To remove a node, if given the node to remove, you will need to check it's Previous and Next properties and (assuming one or both isn't null - you'll need to add logic for that), you set your nodes Previous.Next to your nodes Next and your nodes Next.Previous to your nodes Previous. This will cause your node to fall out of the list (you can set your nodes Next and Previous to null if required, but it's not strictly necessary unless your removed node is going to hang around).
Hopefully that gets you started. Clarify with your tutor, check your textbook (probably better to try and match their terminology if it differs from mine) and also search for "linked list" and "doubly linked list" on the internet. You should find plenty of resources.

Building a Tree menu with recursion in MVC4 - which data structure to use?

I'm building an application with MVC4 that handles Boxes. A Box can contain many boxes and may contain a Box. The menu should look like this:
> Box 1
> Box 2
> Box 2.A
> Box 2.B
> Box 2.C
> Box 2.C.1
> Box 2.D
> Box 3
Right now I have the following:
public object GetTree(Box? box){
foreach (var box in box.Boxes)
{
GetTree(box)
// append menu item with box.name, box.id pair so a link can get generated
}
I'm a little bit stuck though. The menu will get passed as an object to a client, which will somehow display it as a tree menu of links. What data structure is most appropriate here?
Here is all about recursion and a proper data structure.
So here is all about recursion. You already started implementing that way, so this is good.
First things first. Data structure. To represent the tree like menu you should build tree like liked object, so you have to create simple graph of them. You started well. You have a Box object. Lets now enhance it. Create a BoxNode object that have a List of Boxes, like so:
public class BoxNode
{
public List<Box> BoxChildren
{
get; set;
}
}
Then Box:
public class Box
{
public string Name
{
get; set;
}
public BoxNode BoxNode
{
get; set;
}
}
So now we have the basic data structure, lets go to the function:
public static void CreateMenuTree(BoxNode boxNode, string indent)
{
foreach (Box box in boxNode.BoxChildren)
{
Console.WriteLine(indent + box.Name);
if (box.BoxNode != null && box.BoxNode.BoxChildren != null && box.BoxNode.BoxChildren.Count > 0)
{
CreateMenuTree(box.BoxNode, indent + indent);
}
}
}
Here I also created a fully workable code: Gist code for this question*
Please note for the MVC scenario of course you replace the Console.WriteLine with the proper url link generation and indent with some kind CSS class. But I guess you should get the point.
*Please note that this is not a production code, but a DEMO one.

Selenium2 Webdriver C# .Click() List - Stale Reference Exception

I need some help because I keep getting a StaleElementReference when I try to parse a list of a tags to click.
What I have done is on page land I iterate through the page and generate an object List<> with with all the a tags
private List<IWebElement> _pageLinks;
public List<IWebElement> pageLinks
{
get
{
if (_pageLinks == null)
{
_pageLinks = InfoDriver.FindElements(By.TagName("a")).ToList();
}
return _pageLinks;
}
}
Then I want to parse this list, and click each one and then go back to the page it was referenced from.
private static SeleniumInformation si = new SeleniumInformation(ffDriver);
si.pageLinks.ForEach(i =>
{
i.Click();
System.Threading.Thread.Sleep(1000);
ffDriver.Navigate().Back();
});
What happens is that after the first click it goes to the new page and then goes back to the starting page but it can't get the next link. I've tried setting it to a static element, setting a backing field so that it checks to see if there is data there already however it appears that on click the IwebElement looses the list and it doesn't rebuild the list either so I get a StaleElementReference exception not handled and element not found in cache.
Is this a bug in Selenium with the IWebElement class or am I doing something wrong? Any help would be greatly appreciated.
This is the expected behavior. You left the page the element was on. When you navigated back, it is a new page and that element is no longer on it.
To work around this I would suggest passing around Bys instead, if you can. Assuming your anchorlinks all have unique hrefs, you could instead generate a list as follows (java code, but should translate to c#):
private static List<By> getLinks(WebDriver driver)
{
List<By> anchorLinkBys = new ArrayList<By>();
List<WebElement> elements = driver.findElements(By.tagName("a"));
for(WebElement e : elements)
{
anchorLinkBys.add(By.cssSelector("a[href=\"" + e.getAttribute("href") + "\"]"));
//could also use another attribute such as id.
}
return anchorLinkBys;
}
I don't know the makeup of your page so I don't know if it is possible to generate By's dynamically that uniquely identify the elements you want. For example if all the elements have the same parent, you could use the css level 3 selector nth-child(n). Hopefully you get some ideas from the above code.
private void YourTest()
{
IWebDriver browserDriver = new FirefoxDriver();
browserDriver.Navigate().GoToUrl(pageUrl);
int linkCount= browserDriver.FindElements(By.TagName("a")).Count;
for (int i = 0; i <= linkCount-1; i++ )
{
List<IWebElement> linksToClick = browserDriver.FindElements(By.TagName("a")).ToList();
linksToClick[i].Click();
System.Threading.Thread.Sleep(4000);
if(some boolean check)
{
//Do something here for validation
}
browserDriver.Navigate().Back();
}
broswerDriver.Quit();
}

Find controls in listview item template of the same type

I am working on claim expenses application for the staff where I work. Part of the process contains a listview, part of a new requirement is that if an expense type is mileage the user will not be able to edit the item, only delete and resubmit as part of business rules and UK tax reasons etc.
Anyway, I want to be able to find a control in each item of the listview that has a certain text value.
I thought something like the following but this is not correct and I know why.
Label ExpenseTypeLabel = (Label)Expenses.FindControl("ExpenseTypeLabel");
string ExpenseType = (ExpenseTypeLabel.Text.ToString());
if (ExpenseType == "Mileage")
{
foreach (ListViewDataItem thisItem in Expenses.Items)
{
ImageButton btnEdit = (ImageButton)thisItem.FindControl("btnEdit");
btnEdit.Enabled = false;
}
}
The expenses are based on weekending and as the page loads it throws my excepion as It cannot bind to a particular individual control as there are many ExpenseTypeLabels associated with the expense for the current weekending (which loads first).
What I am trying to accomplish here is to find all ExpenseTypeLabels in both the item template and the alternating item template and disable the edit function of that expense item. FYI incase you're wondering the weekending is the expense, and the children are the individual expense items.
Could one of you lovely people please educate me on the best way to accomplish this?
Thanks
Matt
Binding order, and timing for accessing bound items, is extremely important; this is especially true when you have sub controls that have binding items also.
If you want to affect the the display for these bound controls, you can usually do it from the aspx end.
Create a link from the front end to a function on the server end, then pass it all the necessary parameters:
<asp:listview id='lstExpense'>
...
<asp:button id='btnEdit' enabled='<%#= isEnabled(((Expense)Container.DataItem).ExpenseType) %>' ...
...
<asp:listview>
On the server end, make a public function to return that value:
public boolean IsEnabled(string ExpenseType) {
return ('Mileage' != ExpenseType);
}
Best solution though, is to use jQuery. Not exaggerating, but you can accomplish all of that with something as simple as:
$('.rowClass').each(function() {
if ($(this).find('.expenseTypeClass').val() == 'Mileage'))
$(this).find('.btnEditClass').attr('disabled','disabled');
})
use OnItemDataBound event as follows
OnItemDataBound="Expenses_ItemDataBound"
protected void Expenses_ItemDataBound(object sender, ListViewItemEventArgs e)
{
if (e.Item.ItemType == ListViewItemType.DataItem)
{
Label ExpenseTypeLabel = (Label)e.Item.FindControl("ExpenseTypeLabel");
string ExpenseType = (ExpenseTypeLabel.Text.ToString());
if (ExpenseType == "Mileage")
{
// disable button
}
}
}

How do I stop items in a ContextMenuStrip from treating ampersands specially?

I have a ContextMenuStrip which displays items which can be named by the user; the user is allowed to give the items names containing ampersands. When the ContextMenuStrip is shown, the items' treat the ampersands as escape sequences, and underline the next character.
I could double up all the ampersands before I set the items' Text members, but that member is used elsewhere in the code so if possible, I'd like to stop the ContextMenuStrip from treating ampersands specially. Is there a way to turn that behaviour off?
use && to display a single &
Edit: Sorry, I missed the second part of your question :(
You could always use string.Replace("&", "&&") on the text when you set it, but that seems messy.
Another alternative would be to inherit from ToolStripMenuItem and override the Set of the Text Property to replace & with &&. That would be a little better as it would keep the code in once place.
I don't think that there is any built in support for that (like the UseMnemonic property of the Button control), unfortunately. One way to do it is to make a brute-force method that will walk the control tree on the form and perform a replace on all ToolStripMenuItems found:
public TheForm()
{
InitializeComponent();
FixAmpersands(this.Controls);
}
private static void FixAmpersands(Control.ControlCollection controls)
{
foreach (Control control in controls)
{
if (control is ToolStrip)
{
FixAmpersands((control as ToolStrip).Items);
}
if (control.Controls.Count > 0)
{
FixAmpersands(control.Controls);
}
}
}
private static void FixAmpersands(ToolStripItemCollection toolStripItems)
{
foreach (ToolStripItem item in toolStripItems)
{
if (item is ToolStripMenuItem)
{
ToolStripMenuItem tsmi = (ToolStripMenuItem)item;
tsmi.Text = tsmi.Text.Replace("&", "&&");
if (tsmi.DropDownItems.Count > 0)
{
FixAmpersands(tsmi.DropDownItems);
}
}
}
}
This is, of course, useful primarily if the menu structure is not build up dynamically and occasionaly during the lifetime of the form. If new items are added every now and then you will probably need to run them through some method that will perform the ampersand-doubling at on a single item.

Categories