Pattern to map Generic Data Structure to a Specific Data Structure - c#

I have a hierarchical generic data structure. There is a root node and under that there can be many tree nodes, or just a single data node, and tree nodes can have more tree nodes. A basic tree structure.
All data in my system is persisted in this format. I do however want to have a strongly typed interface to some of the different types of data that these data structures represent (ie. turn a generic hierarchical tree into a strongly typed address record).
I was planning on using an adapter pattern where I pass in a node to the adapter and it then exposes properties by interrogating the tree. This would also allow me to validate the tree (ie. that is has specific elements and that they have valid data in them). It also allows for extensibility (ie. the tree itself would also be exposed if there were additional data that was added at a later date).
Do you think this is the most optimal approach to achieve this or is there a simpler way?
Note: this is in C# and .Net 4.0.
Thanks!

An Adapter is usually used to bridge between two incompatible interfaces. That doesn't seem to be your problem here. In fact, I don't really see any problem -- as object languages are by nature hierarchical, you should be able to use a mostly 1-to-1 mapping between a class and a tree node.
Perhaps by "Adapter" you just mean a class that wraps a Node or whatever particular Object type that describes your tree nodes, and I'd agree. There should be fairly obvious parent-child relationships that you can describe by having your node classes own or somehow return an array of child node/classes, and the attributes as getters/setters. Any needed validation could be done by the setters, or if need be during construction as a class inspects a given node and its child nodes. Something like the following:
public class NodeFu {
private Node node;
public NodeFu(Node node){
this.node = node;
// perhaps traverse and validate node data here
}
public String getNodeAttribute(String attrName){
// pardon the offense, Demeter, only for demonstration...
return node.getAttributes().getNamedItem(attrName).toString();
}
public void setNodeAttribute(String attrName, attrValue){
node.setAttributeValue(attrName, attrValue);
}
public ArrayList<NodeFu> getChildren(){
ArrayList<NodeFu> children = new ArrayList<NodeFu>();
for (Node childNode : node.getChildNodes()){
children.add(new NodeFu(childNode));
}
return children;
}
}
I'm assuming you have more business logic to add to this class that will manipulate the data on the Node itself, otherwise the Node class would suffice and you could just use it directly.

Related

MVVM: Extending a Read-Only Model with IsExpanded and IsSelected in TreeViewItem

Consider a ViewModel that exposes a tree defined in the Model, which is then data-bound to a TreeView. The tree is rather large and the model is used directly because it is essentially read-only with regards to the view. Now, the TreeView lives under a TabControl in the VisualTree, so an issue at this point is that the IsExpanded and IsSelected properties aren't preserved when switching between tabs. One hesitates to add these boolean properties to each node in the Model, as this should be extended in the ViewModel as a matter of principle. The tree is composed of polymorphic nodes, so if we were to create a ViewModel node type that derives from the tree node types and adds these properties, it seems this would result in some hairy code in the ViewModel:
That is, if the tree has an abstract NodeBase, and then derived types Node1, Node1, ... NodeN (the Model's Nodes). The ViewModel then has to encapsulate these nodes, so when creating a ViewModelNode, if it has a reference to Node and also references to child ViewModelNode's for each descendent ViewModelNode that encapsulates each descendent Model's Node all the way down the tree, maintaining these child references in the ViewModel identically to how they are maintained in the Model, along with a reference to the Model. i.e. all references in the Model nodes are replicated in the ViewModel nodes, in order for each Model node to be encapsulated by a ViewModel node. The existence of redundant references such as this, even if handled in the ViewModelNode's constructor, just smells bad.
What is the most accepted means to extend each node in a tree in this scenario, without wholesale replication of the references as stated above? (And to a lesser point, is the mere mention of using the model directly by the view an unforgivable crime, or is this forgiven due to the circumstances?)
There is perhaps an argument to be made that implementing those Boolean properties on the Model is OK, but personally I would look to creating ViewModels for each Model that's going to be in the TreeView. One advantage of doing so would perhaps be an increase in scalability, should you ever decide to implement more functionality related to the TreeView.
I think it depends on how much you are actually doing with the TreeView (within your app), but I do think the more you're doing, the stronger the argument for a ViewModel-based solution.
With regards to the hairy code, you could perhaps circumvent this to a degree by using an interface to describe your TreeView members, e.g.:
public interface IMyTreeViewItem
{
bool TreeViewItemIsSelected { get; set; }
bool TreeViewItemIsExpanded { get; set; }
// Further potential properties
string TreeViewItemHeaderText { get; set; }
List<IMyTreeViewItem> TreeViewItemChildren { get; set; }
}
This approach can be used to ensure that your TreeView members are properly "subscribed". There's also then an option to reference the interface type in XAML, for example, as the TargetType of a HierarchicalDataTemplate for the TreeView.

Extending the TreeView control for incremental filtering/searching

I'm trying to extend the winforms TreeView control to allow incremental filtering and searching similar to the Solution Explorer in VS2012/VS2013.
Ideally, I would like it to be capable of replacing the existing TreeView with minimal code change - as far as the consumer is concerned, the only difference would be a method void Filter(string). Because of this, I think it would make sense for the Nodes property to return the TreeNodeCollection with ALL nodes, even ones not showing because of an applied filter.
I have the code written to handle the filtering, and it actually works quite well except when I access base.Nodes, it returns my filtered nodes and not the full list.
The problem I have is, I'm unable to clone or create a new instance of TreeNodeCollection, because the constructor is marked as internal. So my ideal code would look something like this:
public class TreeViewEx : TreeView
{
// results in a compiler error:
private TreeNodeCollection _allNodes = new TreeNodeCollection();
public new TreeNodeCollection Nodes { get { return _allNodes; } }
public TreeNodeCollection FilteredNodes { get { return base.Nodes; } }
public void Filter(string searchString)
{
base.BeginUpdate();
base.Nodes.Clear();
foreach (TreeNode node in FilterInternal(_allNodes, searchString))
{
base.Nodes.Add(node);
}
base.EndUpdate();
}
}
So as you can see, I'm trying to decouple the nodes that are shown in the UI from the nodes that the consumer would access. Of course with TreeNodeCollection having an internal constructor only, I'm unable to create a new instance or clone it.
I considered these two options, but neither sound like good solutions:
Use reflection to instantiate the TreeNodeCollection object (due to the internal constructor) for the second list. This option seems like it would be more efficient than #2, but of course I'm creating an instance of an object I'm not supposed to.
Instantiate a second TreeView in memory and use the Nodes property from that to maintain my second list. This seems like it might be a lot of overhead.
I want the end result to still be a TreeNodeCollection so the TreeView can be used to replace our existing controls with minimal code and we do have several places using the Find method, which doesn't exist in List<TreeNode>.
Does anyone have any recommendations on how to handle this? What about performance/resource-wise with my two considerations?
Thank you
Update 1:
Per Pat's recommendation, I decided to take a step back and avoid messing with Nodes altogether. So now I've added a List<TreeNode> AllNodes property and have the Nodes just display the nodes that appear in the TreeView (the filtered list), so now it's a bit simpler.
My problem now is, how do I know when AllNodes has an item added to it so I can keep Nodes in sync? I've considered using a BindingList so I have the ListChanged event, but then I would need to have my TreeNode and node's children/grand-children/etc (AllNodes[0].Nodes) use a custom class that inherits from TreeNode and change the Nodes property, and TreeNode.Nodes isn't overridable. Is there another way? I could make a new property called NodeExs or something, but that seems very unintuitive and I could see another dev coming along later and pulling his hair out because the Nodes property is there but doesn't work.
With regard to your proposed solutions, #2 is out because a TreeNode cannot belong more than one control. And while it might be possible to create an instance of TreeNodeCollection via reflection, it won't be very useful because its designed to be coupled to a TreeView or another TreeNode. You won't be able to add/remove nodes from the collection.
Because of this, I think it would make sense for the Nodes property to
return the TreeNodeCollection with ALL nodes, even ones not showing
because of an applied filter.
I disagree, the TreeNodeCollection returned by the Nodes property is used by the framework and OS to render the control. You really don't want to hide this property or alter its functionality.
If a consumer needs to have access to _allNodes, create a List<TreeNode> AllNodes property or use a custom collection.
I've found out that the TreeNodeCollection should only be used to read the listed nodes. Instead, I've used List<TreeNode> to list nodes. In my project, I created a List<TreeNode> for each level on the TreeView. I filled the lists at the same time when I filled the TreeView, at the startup. In the end, I used AddRange() to make and combine a list of the all nodes. This way I had all the nodes listed and categorized.
It's easy and fast to create this kinds of lists. I also created a List<string> version of the all nodes list, which I set up as an AutoCompleteCustomSource for my TextBox. This way I was able to use TextBox with AutoComplete for searching the nodes.
I'd make different lists for the consumers and other categories. Then I'd only add the items to the TreeView which meet the given criteria. You can also use treeView.Nodes.Remove() to remove any nodes. You'd still have the actual node stored on the lists, and could add it back again later.
These are just some ideas.

Tree structure +2 children

I implemented a tree structure in c# where a node looks like the following
public class Node
{
public int ID{get;set;}
public string Name{get;set;}
public Node Parent {get;set;}
public IList<Node> Children{get;set;}
public IList<Object> Items{get;set;}
public IEnumerable<Ancestors> {get{return this.GetAncestors();}}
}
I want to improve my structure but i am not sure what is this kind of tree is called, its not a binary tree since the children count varies and can be more than 2, i use recursion for almost every operation from getting a node by Name,Id or reference to removing nodes, in my case when a node is removed i add both the Items and Children Properties to the Parent node.
I did it from scratch and i am sure someone did it better, so could you please help me figure the name of this tree structure so i can google it for improvements?
k-ary tree is probably the closest to what you're looking for. This typically refers to a tree where each node has at most k children (for some k, e.g. a binary tree is a 2-ary tree).
If you're looking for the case where the number of children per node is unbounded, I don't believe that has a specific name, it's just called a tree (although I imagine some resources might call that a k-ary tree as well).
An obvious place for improvement I see here is to use generics for your structure (you should replace IList<Object> with a generic data type, and rename Items to Data ... probably).
Without knowing what you want to do, I can't say whether IList<Object> is a good idea - an alternative might be to have a class with members with specific types instead, or IList<SomeOtherType>.
Having each node store a reference to its parent is not that typical, but if there's a need for it, it can be done.
There are a few places where these structures are also called n-ary trees . If you want examples , you can google for Tries and B-tree.
I think a trie comes closest to what you are trying to structure

C# parent/child data structure availability?

is this type of data structures available in c# or as a free class library somewhere?
I want a multiple parent, multiple child type of data structure such as:
public class Many2ManyNode
{
public List<Object> Parents;
public List<Object> Children;
}
Its like a tree structure but with multiple parents and multiple child.
I'll stand by my previous comments that it looks like you want a directed graph (depending on how you want to use this structure), but if you just wanted to make your code better reflect what you're asking for it would be:
public class Node
{
public List<Node> Parents;
public List<Node> Children;
}
I found this QuickGraph library which was both compiled for silverlight and .net3.5. It also contains AI algorithms and other advance searching.
I'm not aware of any data structure in the framework that does what you are after.
There is a nice MSDN post that covers implementing data structures that will give you what you want. See An Extensive Examination of Data Structures Using C# 2.0
In particular look at part 5 on graphs.
You could try this library. Not sure if that will help or not. Generally I've found that I could aggregate the available generic classes to build the data structures that I have needed. Although the applications I have been working on were not overly concerned with large structures or high search performance.

Put linq to sql results into hierarchical structure for using in a un-ordered list ( for jquery tree )

I have 5 tables in a L2S Classes dbml : Global >> Categories >> Sub-Category >> Item >> Item Data. I want to be able to navigate from the Global table down a tree like structure to get to the items - displaying the title from the Item Data table.
I have an existing control that uses a IHierarchyData / IHierarchicalEnumerable extended collection by iterating over the collection to output an un-ordered list which I then turn into a tree with jquery. I did it based on Return Un-Ordered List from hierarchical sql data
Is there an easy generic way that I could use to put the data from the above table structure into a a Hierarchical structure so that I could re-use my existing control and and just pass in a different collection.
Have you tried Nested Listviews? I have implemented this solution in several pages. I use ObjectDataSources instead of LinqDataSources directly to keep my data logic separate, but the nested EntitySets work beautifully.
I think what is hanging you up is that you don't need four tables to do this.
Look at Return unordered list from hierarchical sql data again. There aren't four tables there. There's only one.
You can use the Union operator to mash your four tables together.
http://weblogs.asp.net/zeeshanhirani/archive/2008/04/11/union-operator-part-12.aspx
Since you are dealing different types in this case, you will have to implement a common interface on each of them to make the code generic. The basic approach would be to create an interface that includes any needed properties (e.g. DisplayText, ActionURL, etc) then iterate over the collection recursively.
Here's a rough example:
public interface IDataItem
{
string DisplayText { get; }
string ActionUrl { get; }
bool HasChildren { get; }
IEnumerable<IDataItem> GetChildren();
}
public void CreateTree(HtmlTextWriter writer, IEnumerable<IDataItem> collection)
{
writer.WriteFullBeginTag("ul");
foreach (var data in collection)
{
writer.WriteFullBeginTag("li");
writer.WriteBeginTag("a");
writer.WriteAttribute("href",data.ActionUrl);
writer.Write(HtmlTextWriter.TagRightChar);
writer.Write(data.DisplayText);
writer.WriteEndTag("a");
if(data.HasChildren)
CreateTree(writer, data.GetChildren());
writer.WriteEndTag("li");
}
writer.WriteEndTag("ul");
}
You will have to implement the interface on each of your types that you want included in the treeview. The just pass in the collection of the top level type and the method above will walk down the hierarchy creating the needed nested list.

Categories