I have a method called GetMenuItems which returns Heirarchical results. Here is the implementation:
public static ObservableCollection<MenuItem> GetMenuItems()
{
XDocument xDoc = XDocument.Load(DirectoryPaths.DataDirectory_General + "MenuItems.xml");
return LoadMenuItems(xDoc.Descendants("MenuItem"));
}
private static ObservableCollection<MenuItem> LoadMenuItems(IEnumerable<XElement> menuItems)
{
return new ObservableCollection<MenuItem>(
menuItems.Select(
x => new MenuItem()
{
Id = Convert.ToDouble(x.Attribute("Id").Value),
Name = x.Element("Name").Value,
ImageData = x.Elements("ImageData").Any() ? x.Element("ImageData").Value : "",
Angle = x.Elements("Angle").Any() ? Convert.ToDouble(x.Element("Angle").Value) : 0,
ScaleX = x.Elements("ScaleX").Any() ? Convert.ToInt32(x.Element("ScaleX").Value) : 0,
ScaleY = x.Elements("ScaleY").Any() ? Convert.ToInt32(x.Element("ScaleY").Value) : 0,
ShortcutKey = x.Elements("ShortcutKey").Any() ? x.Element("ShortcutKey").Value : "",
Background = x.Elements("Background").Any() ? x.Element("Background").Value : "#FF000000",
MouseOver = x.Elements("MouseOver").Any() ? x.Element("MouseOver").Value : "#FF696969",
menuItem = x.Elements("MenuItem").Any() ? LoadMenuItems(x.Elements("MenuItem")) : null
}
)
);
}
Now I want to get all the direct children of a specific Parent.
To make it more clear let me give an example:
Suppose I want to get all the direct children MenuItems of MenuItem whose Id = 1
.
Please note that I need to use GetMenuItems() method as I am not allowed to access those XML Files.
You should split your task into two parts:
The latter is simple - you just use the menuItem
property, which would be better named Children
or something similar.
I'd tackle the first part by recursion - after making one important change. Instead of the Children
property being null if there are no elements, just let it be an empty collection:
Children = LoadMenuItems(x.Elements("MenuItem")
That way, you can check all the children very easily, even if there aren't any - without any nullity checks. Generally, it's easier to represent a lack of items as an empty collection rather than a null reference.
So, to recursively find a menu item by ID, I'd use:
// TODO: Change the ID type from double to almost anything else. double is a
// *terrible* type to use for IDs.
public MenuItem FindMenuItemById(MenuItem item, double id)
{
return item.Id == id ? item : item.Children
.Select(x => FindMenuItemById(x, id))
.Where(found => found != null)
.FirstOrDefault();
}
That will return null
if there's no such menu item. Then you can just use:
if (item != null)
{
var children = item.Children;
...
}
As an aside, your other properties can be converted much more simply using the conversion operators on XElement
and the null-coalescing operator
// Again, change this! Don't use double!
Id = (double) x.Attribute("Id"),
Name = (string) x.Element("Name"),
ImageData = (string) x.Element("ImageData") ?? "",
Angle = (double?) x.Element("Angle") ?? 0d,
ScaleX = (double?) x.Element("ScaleX") ?? 0d,
ScaleY = (double?) x.Element("ScaleY") ?? 0d,
ShortcutKey = (string) x.Element("ShortcutKey") ?? "",
Background = (string) x.Element("Background") ?? "#FF000000",
MouseOver = (string) x.Element("MouseOver") ?? "#FF696969",
See more on this question at Stackoverflow