
Design Question: TreeView (GUI) & Composite Pattern (MODEL)
Hello,
I have a composite pattern with an abstract class "Component" and with
subclasses "Leaf" and "Node".
The composite pattern is the MODEL. Now I want to map the composite to the
TreeView, more specifically
to the TreeNodeCollection. So I have a function like below:
public void TraverseTree(Component node, TreeNode tNode)
{
node.OnComponentChanged += new ComponentChangedHandler(ComponentChanged);
if (node is Node)
{
Node aNode = (Node)node;
TreeNode childNode = new TreeNode(aNode.Name);
childNode.Tag = aNode;
tNode.Nodes.Add(childNode);
IEnumerator ienum = aNode.GetEnumerator();
while(ienum.MoveNext())
TraverseTree((Component)ienum.Current, childNode);
}
else if(node is Leaf)
{
Leaf aLeaf = (Leaf)node;
TreeNode f = new TreeNode(aLeaf.Name);
f.Tag = aLeaf;
tNode.Nodes.Add(f);
}
Quote:
}
So, in this function I subscribe to changes in the MODEL with the delegate
"ComponentChanged".
And on every TreeNode is set the "Tag" property to the corresponding
component.
The next step is, when we Add a Node in the Treeview we have for example the
following function:
protected void AddNode_Click(object sender, EventArgs e)
{
TreeNode selectedTreeNode = this.SelectedNode;
Node newNode = new Node();
newNode.Name = "TEST";
Component c = (Component)selectedTreeNode.Tag;
c.Add(newNode);
}
Quote:
}
We use the "Tag" property to know on which Component we have to add a child
and we add for example a Node with the name "TEST" to the MODEL.
Now, we have to update the TreeNodeCollection because the model has changed,
so we have to implement the "ComponentChanged" method:
public void ComponentChanged(object o, ComponentChangedEventArgs e)
{
switch (e.Operation)
{
case Operation.Add:
TreeNode treeNode = GetTreeNode(e.Component.Parent);
TreeNode newNode = newNode = new TreeNode(e.Component.Name, 0, 1);
newNode.Text = e.Component.Name;
newNode.Tag = e.Component;
treeNode.Nodes.Add(newNode);
break;
case Operation.Remove: ... break;
case Operation.Update: ... break;
}
Quote:
}
My concern is the GetTreeNode method, which has to traverse the whole
TreeNodeCollection
to know which TreeNode is associated with the Component, with the "Tag"
property. It is some
overhead to traverse each time the TreeNodeCollection when the MODEL
changes.
So the function looks like this (here impemented with a stack, but can also
be done with a recursive function):
private TreeNode GetTreeNode(Component c)
{
Stack stack = new Stack();
if (Nodes.Count > 0)
{
stack.Push(Nodes[0]);
while(stack.Count > 0)
{
TreeNode node = (TreeNode)stack.Pop();
if (node.Tag != null && node.Tag.Equals(c))
return node;
else
foreach(TreeNode childNode in node.Nodes)
stack.Push(childNode);
}
}
return null;
Quote:
}
One solution would be that the Component (MODEL) also has a TAG property
where we TAG to the corresponsing TreeNode as we did in the opposite way.
But I
am not sure If this is the way to do it, if it is a good design! (maybe it
violates the fact that
the MODEL has a reference to the GUI, however the TAG property is of type
object).
Any remarks and suggestions are welcome, certainly when there is a more
elegant way
to do this, I would like to know.
regards
Christoph De Baene