I am using MVVM and it is working all fine, except one thing, accessing parent model objects.
The goal is to access any model object's parent object directly, but I could not find a propper way to do that.
For example:
Grandparents
--- Parents
--- --- Children
--- --- --- Grandchildren
I have a reference to a Child, but I have to check some properties of Children and maybe Parents.
Currently the code is running through all higher level objects until there is a successful match in the Parent's Children's Grandchildren with my Grandchild object, and then it is possible to check the properties.
But this is kind of disgusting in terms of smart code and efficiency, independent of how this is done, I do not want to run through all my data for a lucky match. This is the current imoplementation, some other parts are done by using LINQ.
var someChild = calledChild;
foreach (Grandparent gParent in mainViewModel.SelectedEnvironment.GrandParents)
{
foreach (Parent parent in gParent.Parents)
{
foreach (Child child in parent.Children)
{
if (child.A == calledChild.A)
{
// Match
System.Diagnostics.Debug.WriteLine("CalledChilds grandparent is " + gParent.Name);
}
}
}
}
The model is set up in classes with definitions like this:
public class Parent : ObservableObject
{
public const string NamePropertyName = "Name";
private string _name;
public string Name
{
get
{
return _name;
}
set
{
if (_name == value)
{
return;
}
_name = value;
RaisePropertyChanged(NamePropertyName);
}
}
public const string ChildrenPropertyName = "Children";
private ObservableCollection<Child> _children;
public ObservableCollection<Child> Children
{
get
{
return _children;
}
set
{
if (_children == value)
{
return;
}
_children = value;
RaisePropertyChanged(ChildrenPropertyName);
}
}
}
The model is saved in a json file and parsed back to the model's root object type for usage.
I can not just add a new reference "Parent" to the "Child" object, because it would end up in a loop, due to this concepts restrictions.
It would be great to get references instead of copies of the whole model branch.
Is there a way to access the parent objects directly?
Thank you all!
Easiest way is to store direct reference to parent node in child nodes:
public class ParentNode
{
private ObservableCollection<ChildNode> _children;
public ParentNode()
{
_children = new ObservableCollection<ChildNode>();
Children = new ReadOnlyObservableCollection<ChildNode>(_children);
}
public ReadOnlyObservableCollection<ChildNode> Children { get; }
public void AddChild(ChildNode item)
{
if (item.Parent != null) throw new InvalidOperationException("Item is already added to another node");
item.Parent = this;
_children.Add(item);
}
public void RemoveChild(ChildNode item)
{
if (item.Parent != this) throw new InvalidOperationException("Item is not direct child of this node");
item.Parent = null;
_children.Remove(item);
}
}
public class ChildNode
{
public ParentNode Parent { get; internal set; }
}
just be careful, because this introduces circular references - parent references children and vice versa. It is kind of violation of DRY principle, because the shape of the tree is defined twice and you could easily get out of sync (e.g. you set ChildNode.Parent property to something else than the actual parent).
There are ways to workaround it, but I think you could start with this.
Related
I have a tree structure like this:
public class Node
{
public Node Parent { get; set; }
public List<Node> Children { get; set; }
public NodeValue Item { get; set; }
}
And a NodeViewModel like this:
public class NodeViewModel : INotifyPropertyChanged
{
public Node Node
{
get;
private set;
}
public NodeViewModel(Node node)
{
this.Node = node;
this._children = new ObservableCollection<NodeViewModel>();
}
public string Code {
get
{
return this.Item.Code;
}
set
{
this.Item.Code = value;
NotifyPropertyChanged("Code");
}
}
public Node Parent
{
get
{
return this.Node.Parent;
}
set
{
if (value != this.Node.Parent)
{
this.Node.Parent = value;
NotifyPropertyChanged("Parent");
}
}
}
public NodeValue Item
{
get
{
return Node.Item;
}
set
{
this.Node.Item = Item;
}
}
private ObservableCollection<NodeViewModel> _children;
public ObservableCollection<NodeViewModel> Children
{
get
{
_children.Clear();
foreach(var child in Node.Children)
{
_children.Add(new NodeViewModel(child));
}
return _children;
}
protected set
{
this._children = value;
NotifyPropertyChanged("Children");
}
}
The problem is the last property because when I want to update the model using view model, for example when I want to add a new node I must update _children ObservableCollection from NodeViewModel and also Children List<Node> from Node class.
If I update only the model the UI does not update because NotifyPropertyChanged isn't called and if I update only the view, the changes will be lost because the getter will create another ObservableCollection and also the changes are not reflected over the model.
How can I update the model through view model class?
Whichever way you slice it, the view model needs to fully encapsulate the model. If you had a "save" command you could just update/recreate the model's collection at that time.
Assuming you don't have a "save" command though, and the model should always reflect the current state of the view model, one option is to subscribe to the ObservableCollection<T>.CollectionChanged event and update the underlying collection on the fly.
A side note, you most likely also don't want to create a new collection every time Children_get is called, and are better off just lazy-loading one you keep around.
ObservableCollection already implements INotifyPropertyChanged.
However it will only work if the count of the collection changes.
Also why do you want a ViewModel Collection?
But I think you're looking for this implementation:
private ObservableCollection<Node> _children;
public ObservableCollection<Node> Children {
...code logic
}
Don't forget to handle the changed event
I want to make a tree structure that takes in strings and displays everything in the tree. Please note that the purpose here is not to make a binary search tree or anything related to binary tress, rather it will be modelled on the the basis of: the first string entered is the "root", the second string is a parent, and the third is a child of the parent node. Please see illustration. The number of parent nodes can be however many.
Basically, I would like some ideas on how to approach this. I'm familiar with how a binary tree is coded and how it works, but this one seems a lot more different to implement.
In your case, it is a simple tree composed of a collection of nodes (multiple children), where each child has some associated data and a set of children. With this in mind, lets have a type called Node which will act as a building block of our tree. And try to abstract out as base Node class that can be extended to meet the needs of a tree node through inheritance.
Note: I am going to make it generic to be able to store any type though you wanted to store 'String'.
public class Node<T>
{
// Private member-variables
private T data;//This member variable contains the data stored in the node of the type specified by the developer using this class.
private NodeList<T> neighbors = null; //of type `NodeList<T>`. This member variable represents the node's children.
public Node() {}
public Node(T data) : this(data, null) {}
public Node(T data, NodeList<T> neighbors)
{
this.data = data;
this.neighbors = neighbors;
}
public T Value
{
get
{
return data;
}
set
{
data = value;
}
}
protected NodeList<T> Neighbors
{
get
{
return neighbors;
}
set
{
neighbors = value;
}
}
}
}
The NodeList class contains a strongly-typed collection of Node<T> instances.This class is derived from the Collection<T> in order to have a strong-typed collection, with methods like Add(T), Remove(T), and Clear() etc. Important thing to notice here is that, the arbitrary ('n') number of nodes can be added through the constructor that creates a specified number of nodes in the collection, and a method that searches the collection for an element of a particular value.
public class NodeList<T> : Collection<Node<T>>
{
public NodeList() : base() { }
public NodeList(int initialSize)
{
// Add the specified number of items
for (int i = 0; i < initialSize; i++)
base.Items.Add(default(Node<T>));
}
public Node<T> FindByValue(T value)
{
// search the list for the value
foreach (Node<T> node in Items)
if (node.Value.Equals(value))
return node;
// if we reached here, we didn't find a matching node
return null;
}
}
Finally, we left out with joining all what we discussed.
public class SpecialTree<T> : Node<T>
{
public SpecialTree() : base() {}
public SpecialTree(T data) : base(data, null) {}
public SpecialTree(T data, SpecialTree<T> left, SpecialTree<T> right)
{
base.Value = data;
NodeList<T> children = new NodeList<T>(2);
children[0] = left;
children[1] = right;
base.Neighbors = children;
}
public SpecialTree<T> Left
{
get
{
if (base.Neighbors == null)
return null;
else
return (SpecialTree<T>) base.Neighbors[0];
}
set
{
if (base.Neighbors == null)
base.Neighbors = new NodeList<T>(2);
base.Neighbors[0] = value;
}
}
public SpecialTree<T> Right
{
get
{
if (base.Neighbors == null)
return null;
else
return (SpecialTree<T>) base.Neighbors[1];
}
set
{
if (base.Neighbors == null)
base.Neighbors = new NodeList<T>(2);
base.Neighbors[1] = value;
}
}
}
There are no built in classes in .NET for manipulating tree structures and the simple reason is that there are too many variations.
I’d suggest you make your own class that would represent binary tree. Take a look at these threads for more details.
Why is there no Tree<T> class in .NET?
Tree data structure in C#
I have a class that may have a parent, or list of children of the same type of it's own. The following code snippet should explain my scenario.
public abstract class X{
public virtual List<X> ChildItems { get; set; }
public virtual X ParentItem { get; set; }
}
I would like to know if there is a particularly efficient method to traverse the objects from an object of type X, checking if the object has a parent, or children starting from bottom up.
public static void SaveSetup(X obj) {
//logic here
}
Any help is appreciated.
What you are dealing with is a tree structure (or possibly many disconnected tree structures). A tree structure has a root element. Usually, a tree structure is traversed starting from the root. If you want to start from any element in the tree, I suggest you to first get the root element and then traverse in the usual manner.
The easiest way to traverse a recursive structure is to use recursive method, i.e., a method that calls itself.
public abstract class X
{
public virtual List<X> ChildItems { get; set; }
public virtual X ParentItem { get; set; }
// Method for traversing from top to bottom
public void Traverse(Action<X> action)
{
action(this);
foreach (X item in ChildItems) {
item.Traverse(action);
}
}
// Get the root (the top) of the tree starting at any item.
public X GetRootItem()
{
X root = this;
while (root.ParentItem != null) {
root = root.ParentItem;
}
return root;
}
}
Now you can save the setup with
X root = item.GetRootItem();
root.Traverse(SaveSetup);
Example with lambda expression. Prints every item of the tree assuming that ToString() has been overridden to return a meaningful string.
root.Traverse(x => Console.WriteLine(x));
Traverse from given object to root (ParentItem = null)
public static void SaveSetup(X obj) {
while (obj != null)
{
// logic here
obj = obj.ParentItem;
}
}
So I have 2 interfaces:
A node that can have children
public interface INode
{
IEnumeration<INode> Children { get; }
void AddChild(INode node);
}
And a derived "Data Node" that can have data associated with it
public interface IDataNode<DataType> : INode
{
DataType Data;
IDataNode<DataType> FindNode(DataType dt);
}
Keep in mind that each node in the tree could have a different data type associated with it as its Data (because the INode.AddChild function just takes the base INode)
Here is the implementation of the IDataNode interface:
internal class DataNode<DataType> : IDataNode<DataType>
{
List<INode> m_Children;
DataNode(DataType dt)
{
Data = dt;
}
public IEnumerable<INode> Children
{
get { return m_Children; }
}
public void AddChild(INode node)
{
if (null == m_Children)
m_Children = new List<INode>();
m_Children.Add(node);
}
public DataType Data { get; private set; }
Question is how do I implement the FindNode function without knowing what kinds of DataType I will encounter in the tree?
public IDataNode<DataType> FindNode(DataType dt)
{
throw new NotImplementedException();
}
}
As you can imagine something like this will not work out
public IDataNode<DataType> FindNode(DataType dt)
{
IDataNode<DataType> result = null;
foreach (var child in Children)
{
if (child is IDataNode<DataType>)
{
var datachild = child as IDataNode<DataType>;
if (datachild.Data.Equals(dt))
{
result = child as IDataNode<DataType>;
break;
}
}
else
{
// What??
}
// Need to recursively call FindNode on the child
// but can't because it could have a different
// DataType associated with it. Can't call FindNode
// on child because it is of type INode and not IDataNode
result = child.FindNode(dt); // can't do this!
if (null != result)
break;
}
return result;
}
Is my only option to do this when I know what kinds of DataType a particular tree I use will have? Maybe I am going about this in the wrong way, so any tips are appreciated. Thanks!
First of all, you need to put the FindNode method in INode. Otherwise, you cannot find a node of some type DataType... before having found a node of type DataType. Even if you have a reference to an object that you know is a DataNode<X>, this won't help you if someone tells you to find a DataNode<Y>.
There are now two roads you may take: if you want DataNode to be templated, then you need to know all possible types of data in the tree at compile time. If you know that, you can use a generic DataNode. If there's a chance that you may want to find a node with data of some type that will only become known to you at runtime (e.g. from the return value of some method that you do not control) then you cannot use generics.
I will illustrate the generic solution below.
public interface INode
{
IEnumerable<INode> Children { get; }
IDataNode<DataType> FindNode<DataType>(DataType value);
void AddChild(INode node);
}
public interface IDataNode<DataType> : INode
{
DataType Data { get; }
}
INode.FindNode could be implemented like this:
public IDataNode<DataType> FindNode<DataType> (DataType value) {
// If we are searching for ourselves, return this
var self = this as IDataNode<DataType>;
if (self != null && self.Data.Equals(value)) {
return self;
}
// Otherwise:
// 1. For each of our children, call FindNode on it. This will
// find the target node if it is our child, since each child
// will check if it is the node we look for, like we did above.
// 2. If our child is not the one we are looking for, FindNode will
// continue looking into its own children (depth-first search).
// 3. Return the first descendant that comes back and is not null.
// If no node is found, FirstOrDefault means we will return null.
return this.children.Select(c => c.FindNode(value))
.FirstOrDefault(found => found != null);
}
I have to say that the above recursive implementation with LINQ tries perhaps to be too clever and is maybe not very easy to understand. It could always be written with foreach, to make it more clear.
Use a Generic Function:
public IDataNode<DataType> FindNode<DataType>(DataType dt)
{
IDataNode<DataType> result = null;
foreach (var child in Children)
{
if (child is IDataNode<DataType>)
{
var datachild = child as IDataNode<DataType>;
if (datachild.Data.Equals(dt))
{
result = child as IDataNode<DataType>;
break;
}
}
else
{
// it's not a DataType You're looking for, so ignore it!
}
}
return result;
}
Then you call it like this:
var resultsStr = tree.FindNode<string>("Hello");
var resultsInt = tree.FindNode<int>(5);
var resultsCust = tree.FindNode<MyCustomClass>(new MyCustomClass("something"));
I'll try to explain this the best I can. I'm having quite a bit of difficulty trying to figure out this logic.
Basically, I have a collection that includes thousands of objects which are each made up of a Parent and a Child property.
So, roughly, this:
public class MyObject{
public string Parent { get; set; }
public string Child { get; set; }
}
What I'm trying to figure out is how to build this out into a plain TreeView control. I need to build the relationships but I can't figure out how to because they can be mixed. I can probably explain this better with what the tree should look like:
So if I have the following items inside of my collection:
0. Parent: "A", Child: "B"
1. Parent: "B", Child: "C"
2. Parent: "B", Child: "D"
I would want my tree to look this like:
-A
--B
---C
-A
--B
---D
-B
--C
-B
--D
How can I do this in C#? I would need it to support up to N relationships as we have some branches I would expect to reach about 50 nodes deep.
UPDATE
This problem actually turned out to be considerably more complex than I originally realized, given the requirement of repeating the entire tree for each path. I've simply deleted the old code as I don't want to add any further confusion.
I do want to keep it on record that using a recursive data structure makes this easier:
public class MyRecursiveObject
{
public MyRecursiveObject Parent { get; set; }
public string Name { get; set; }
public List<MyRecursiveObject> Children { get; set; }
}
You'll see very clearly why this is easier after reading the implementation code below:
private void PopulateTree(IEnumerable<MyObject> items)
{
var groupedItems =
from i in items
group i by i.Parent into g
select new { Name = g.Key, Children = g.Select(c => c.Child) };
var lookup = groupedItems.ToDictionary(i => i.Name, i => i.Children);
foreach (string parent in lookup.Keys)
{
if (lookup.ContainsKey(parent))
AddToTree(lookup, Enumerable.Empty<string>(), parent);
}
}
private void AddToTree(Dictionary<string, IEnumerable<string>> lookup,
IEnumerable<string> path, string name)
{
IEnumerable<string> children;
if (lookup.TryGetValue(name, out children))
{
IEnumerable<string> newPath = path.Concat(new string[] { name });
foreach (string child in children)
AddToTree(lookup, newPath, child);
}
else
{
TreeNode parentNode = null;
foreach (string item in path)
parentNode = AddTreeNode(parentNode, item);
AddTreeNode(parentNode, name);
}
}
private TreeNode AddTreeNode(TreeNode parent, string name)
{
TreeNode node = new TreeNode(name);
if (parent != null)
parent.Nodes.Add(node);
else
treeView1.Nodes.Add(node);
return node;
}
First of all, I realized that the dictionary will contain keys for intermediate nodes as well as just the root nodes, so we don't need two recursive calls in the recursive AddToTree method in order to get the "B" nodes as roots; the initial walk in the PopulateTree method already does it.
What we do need to guard against is adding leaf nodes in the initial walk; using the data structure in question, these are detectable by checking whether or not there is a key in the parent dictionary. With a recursive data structure, this would be way easier: Just check for Parent == null. But, a recursive structure is not what we have, so the code above is what we have to use.
The AddTreeNode is mostly a utility method, so we don't have to keep repeating this null-checking logic later.
The real ugliness is in the second, recursive AddToTree method. Because we are trying to create a unique copy of every single subtree, we can't simply add a tree node and then recurse with that node as the parent. "A" only has one child here, "B", but "B" has two children, "C" and "D". There needs to be two copies of "A", but there's no way to know about that when "A" is originally passed to the AddToTree method.
So what we actually have to do is not create any nodes until the final stage, and store a temporary path, for which I've chosen IEnumerable<string> because it's immutable and therefore impossible to mess up. When there are more children to add, this method simply adds to the path and recurses; when there are no more children, it walks the entire saved path and adds a node for each.
This is extremely inefficient because we are now creating a new enumerable on every invocation of AddToTree. For large numbers of nodes, it is likely to chew up a lot of memory. This works, but it would be a lot more efficient with a recursive data structure. Using the example structure at the top, you wouldn't have to save the path at all or create the dictionary; when no children are left, simply walk up the path in a while loop using the Parent reference.
Anyway, I guess that's academic because this isn't a recursive object, but I thought it was worth pointing out anyway as something to keep in mind for future designs. The code above will produce exactly the results you want, I've gone ahead and tested it on a real TreeView.
UPDATE 2 - So it turns out that the version above is pretty brutal with respect to memory/stack, most likely a result of creating all those IEnumerable<string> instances. Although it's not great design, we can remove that particular issue by changing to a mutable List<string>. The following snippet shows the differences:
private void PopulateTree(IEnumerable<MyObject> items)
{
// Snip lookup-generation code - same as before ...
List<string> path = new List<string>();
foreach (string parent in lookup.Keys)
{
if (lookup.ContainsKey(parent))
AddToTree(lookup, path, parent);
}
}
private void AddToTree(Dictionary<string, IEnumerable<string>> lookup,
IEnumerable<string> path, string name)
{
IEnumerable<string> children;
if (lookup.TryGetValue(name, out children))
{
path.Add(name);
foreach (string child in children)
AddToTree(lookup, newPath, child);
path.Remove(name);
}
// Snip "else" block - again, this part is the same as before ...
}
like rubens, I tried both, but a little better I think A Generic Tree Collection
this tree collection got some nice functionality build-in to move around the tree, go read the whole article
sample with the link above
Static Class Module1
{
public static void Main()
{
Common.ITree<myObj> myTree = default(Common.ITree<myObj>);
myObj a = new myObj("a");
myObj b = new myObj("b");
myObj c = new myObj("c");
myObj d = new myObj("d");
myTree = Common.NodeTree<myObj>.NewTree;
myTree.InsertChild(a).InsertChild(b).InsertChild(c).Parent.Parent.InsertNext(a).InsertChild(b).InsertChild(d).Parent.Parent.InsertNext(b).InsertChild(c).Parent.InsertNext(b).InsertChild(d);
Console.WriteLine(myTree.ToStringRecursive);
Console.ReadKey();
}
}
Class myObj
{
public string text;
public myObj(string value)
{
text = value;
}
public override string ToString()
{
return text;
}
}
would be exactly what you just showed
-A
--B
---C
-A
--B
---D
-B
--C
-B
--D
If I understand this correctly, what you're trying to do is take one tree and transform it into another. The transformation essentially takes each non-leaf-node in the input tree and creates a node for it (and its descendants) in the output tree.
First off, you'll be happier if you design a data structure for your nodes that is genuinely recursive:
public class Node
{
public Node Parent { get; private set; }
public IEnumerable<Node> Children { get; private set; }
public bool HasChildren { get { return Children.Count() > 0; } }
public Node()
{
Children = new List<Node>();
}
}
Your MyObject class represents parent/child relationships between string values. As long as you're able to implement a FindChildren() method that returns the child values for a given parent value, using this class to rationalize the parent/child relationships is straightforward:
public string Value { get; set; }
public static Node Create(string parentKey)
{
Node n = new Node();
n.Value = parentKey;
foreach (string childKey in FindChildren(parentKey))
{
Node child = n.Children.Add(Node.Create(childKey));
child.Parent = n;
}
return n;
}
It's simple to implement a property that returns a node's descendants:
public IEnumerable<Node> Descendants
{
get
{
foreach (Node child in Children)
{
yield return child;
foreach (Node descendant in child.Descendants)
{
yield return descendant;
}
}
}
}
To add a Node to a TreeView, you need two methods. (Note that these aren't methods of the Node class!) I've made them overloads, but an argument can be made for giving them different names:
public void AddNode(Node n, TreeView tv)
{
TreeNode tn = tv.Nodes.Add(n.Value);
tn.Tag = n;
foreach (Node child in n.Children)
{
AddNode(child, tn);
}
}
public void AddNode(Node n, TreeNode parent)
{
TreeNode tn = parent.Nodes.Add(n.Value);
parent.Tag = n;
foreach (Node child in n.Children)
{
AddNode(child, tn);
}
}
I'm setting the Tag on each TreeNode so that you can find your way back to the original Node.
So to initialize your TreeView from a list of top-level parent keys, you need a method like this:
public void PopulateTreeView(IEnumerable<string> parents, TreeView t)
{
foreach (string parentKey in parents)
{
Node n = Node.Create(parentKey);
AddNode(n, t);
foreach (Node descendant in n.Descendants)
{
if (n.HasChildren)
{
AddNode(descendant, t);
}
}
}
}
Edit:
I didn't quite understand how your MyObject class was working; I think I do now, and I've edited this accordingly.