I'm having trouble editing fields/properties in a hierarchical list with the help of a second lookup list. Everything I try looks like a mess and is hard to maintain. Are binary search trees my friend? How would I apply them? Flattening my hierarchical structure doesn't work as I need the hierarchy, just filtered.
public class Filter
{
public string Name {get;set;}
public bool IsActive {get;set;}
public bool IsDisplayed {get;set;}
public string List<Filter> Filters {get;set}
}
public List<string> ActiveFilters {"Green", "LighterYellow", "Red", "Meep")};
My base filters basically look like this:
Colors
Green
Yellow
LightYellow
LighterYellow
OrangishYellow
Red
DarkRed
Sounds
Meep
Moop
Maap
Now I'm trying to set some of these filters to active. But of course the parents of children who are in the ActiveFilters need to be displayed (IsDisplayed) otherwise you wouldn't be able to see the child items.
In the end I want the hierarchy to look like this (based on applying the ActiveFilters, bold indicates IsActive, italic IsDisplayed):
Colors
Green
Yellow
LightYellow
LighterYellow
Red
Sounds
Meep
I have been trying to recursively loop through the hierarchical list, but I don't know how to set the parents to IsDisplayed (as I would have to "go back up"). When looping the other way through the ActiveFilters I don't want to iterate over the whole filter list for each active filter performance wise.
I would do something like this:
First, add a Parent property to Filter
public class Filter
{
public string Name {get;set;}
public bool IsActive {get;set;}
public bool IsDisplayed {get;set;}
public string List<Filter> Filters {get;set}
// Parent
public Filter Parent {get;set;}
}
In your initialization code for the hierarchy, make sure you populate Parent correctly. (I don't know what your code looks like, so I'll leave that part to you.)
Next, in your code that highlights the active filters, do something like:
var parent = activeFilter.Parent;
while (parent != null)
{
parent.IsDisplayed = true;
parent = parent.Parent;
}
Related
Data Types
My MainWindow has a property called Project project which has a property ObservableCollection<Drawable> Drawables
public class Drawable {
public enum DrawableType { Top, Head, Feet };
public bool IsMale {get; set;}
public bool IsFemale {get; set;}
public DrawableType DrawableType {get; set;}
public string DisplayName {get; set;}
}
For all Data types and properties I properly implemented the INotifyPropertyChanged interface.
Current situation
The ObservableCollection is displayed in a ListView but as it contains up to about 500 items it is hard to use the application. I would like to display the items in a TreeView-like structure categorized by the gender (IsMale, IsFemale) and the DrawableType like this:
Male
Top (Drawables are display here if IsMale=true and DrawableType=DrawableType.Top)
Drawable 1
Drawable 2
Drawable 3
Head
Feet
Female
Top (Drawables are display here if IsFemale=true and DrawableType=DrawableType.Top)
Drawable 2
Head
Feet
In this example Drawable 2 has IsFemale=true, the others have false.
My problem
During research I found that ListView actually supports grouping but I don't think this is what I want as a single instance of Drawable can be a children of up to two nodes (as with Drawable 2 belongs both to Male->Top and Female->Top)
What I have tried
I tried using a TreeView which provides all the visuals I need for this task but I can not get it to categorize the Drawable instances. I tried subscribing to the PropertyChanged and CollectionChanged events to create an ObservableCollection in order to create a structure that I can directly bind the TreeView to:
public class DrawableListEntry : INotifyPropertyChanged {
public enum Sex {Male, Female}
public Drawable Drawable;
public DrawableType DrawableType = DrawableType.None;
public Sex Sex = Sex.None;
public string Label {
get {
if(Drawable != null) { return Drawable.DisplayName; }
if(DrawableType != null) { return DrawableType.ToString(); }
return Sex.ToString();
}
}
public ObservableCollection<DrawableListEntry> Children {get; set;}
}
My Question
Is it possible to directly bind to the ObservableCollection and let a TreeView do the categorization automatically?
Please keep in mind, that I'm currently not adhering to any patterns like MVVM but I try to keep my business logic apart from the UI.
During research I found that ListView actually supports grouping but I don't think this is what I want as a single instance of Drawable can be a children of up to two nodes (as with Drawable 2 belongs both to Male->Top and Female->Top)
Create a DrawableViewModel class with Gender, DrawableType and DisplayName properties and then add an instance of this class for each leaf entry that you want to display in the grouped ListView.
In this particular example you will then end up with a source collection of four items; Drawable 1, Drawable 2, Drawable 3 and another Drawable 2 (with the Gender property set to Female unlike the first one).
In other words, you should use the MVVM design pattern to basically transform your data model into something that works with the ListView control in the view.
I have an requirement to show a binary tree like structure on the web page that will
be used to represent parent-child relation. Unlike binary tree, this tree can have multiple child nodes
and the childs can have further children and this process will continue until no child left of their parent.
So, I am pretty much confused on how should my data-model should be and my thinking is not going beyond this one
public class Parent
{
public string parentName {get;set;} // As their will be one start for this tree, I will have one parent node that will show the parent
public List<string> child {get;set;} // As the parent can have multiple children, I can have a list of string
}
But the question is that the child can also act as parent as they can also have children. How should I
implement such structure.
Thanks
A string can't have child elements of its own, so it's not a good representation.
A simple way is to make the child elements simply a List of the same type of element as the parent. Let's call them all Node instead:
public class Node
{
public string Name { get; set; }
public List<Node> ChildNodes { get; set; }
}
I have a List<Leaf> named items in C#. A Leaf has the following properties:
public class Leaf
{
public int ID { get; set; }
public int ParentID { get; set; }
public bool IsFlagged { get; set; }
}
If a Leaf has the IsFlagged property set then I need to remove it from the collection of items. In addition, I need to remove all of that Leaf entity's children. I'm trying to figure out the most elegant way to write this code. Currently, I have a loop within a loop, but it seems sloppy.
Does anyone know of an elegant way to do this?
Perhaps:
void RemoveItAndChildren(Leaf leaf)
{
foreach (Leaf item in items)
if (item.ParentID == leaf.ID)
RemoveItAndChildren(item);
items.Remove(leaf);
}
And use so:
foreach (Leaf leaf in items)
if (leaf.IsFlagged)
RemoveItAndChildren(leaf);
Note that, as in a comment above, something like the following might be more appropriate:
public class Leaf2
{
List<Leaf2> Children;
bool IsFlagged { get; set; }
}
Most reasonable (and probably "the most elegant") way of dealing with tree is to store it as a tree, not an array/list. In this case you'll not need to deal with walking elements to try to find all children.
Note that depending on your actual requirements tree may not be best data structure, but for removing node with all children nodes it would be hard to beat regular tree.
I have the following code:
public class Navigation
{
public Navigation()
{
SubNavigation = new List<Navigation>();
}
public int Order { get; set; }
public string Text { get; set; }
public string RouteName { get; set; }
public IList<Navigation> SubNavigation { get; set; }
}
I then have:
IList<Navigation> list = new List<Navigation>();
I populate the list with some data. Not all items have a sub navigation. Currently the navigation only goes one level deep.
Now I would like to sort both the navigation and the sub-navigation for each item by order. I have tried all kinds of approaches but no matter what I tried I could not get the sub-navigation to sort without re-creating the object. The below code works:
IList<Navigation> result = list.OrderBy(l => l.Order)
.Select(n => new Navigation
{
Order = n.Order,
Text = n.Text,
RouteName = n.RouteName,
SubNavigation = n.SubNavigation.OrderBy(s => s.Order).ToList()
}).ToList();
I am not in love with this approach and my question is if there is any cleaner/better way of doing this using LINQ and the method syntax?
You could add a new property on your object:
public IList<Navigation> OrderedSubNavigation
{
get
{
return SubNavigation.OrderBy(s => s.Order).ToList();
}
}
Then when you want the ordered one you just use that.
I have tried all kinds of approaches but no matter what I tried I could not get the sub-navigation to sort without re-creating the object.
Well no, you wouldn't be able to cleanly - because getting the subnavigation to be in a particular order requires modifying the existing object, and LINQ's not built for that. LINQ's built for queries, which shouldn't mutate the data they work on.
One option would be to only sort the subnavigation when you need to - live with the fact that it's unordered within a Navigation, and then when you actually need the subnavigation items (e.g. for display) you can order at that point. Aside from anything else, this will make it more efficient if you end up not displaying the subnavigation items.
Basically I have a List within a List that i want to bind to a dataGridView. It's like this
public class Town {
public List<Shop> Shops { get; set; }
}
public class Shop {
public List<Car> Cars {get; set; }
}
and the class Cars with some properties and overriding the ToString method.
Now, I want to display on the grid rows the Shops with the Cars's properties in the columns.
I also serialize and deserialize the Town object into an XML. I found a way to modify the DataSource object so it can store user's input, but I cannot display the data from a loaded XML.
It is not apparent what the problem is. From what you've said, it should be fairly straightforward. Deserialize the Town object back into an object graph and you'd be able to do something like this:
var shop = town.Shops[0];
grid.DataSource = shop.Cars;
and that should be enough, provided your grid is correctly configured at design-time.
The Car type must expose its data as public properties for this to work, not as fields.